Recognising the campaign, not the request

Agentic security monitoring for Northwind Projects — a normally secured, multi-tenant project-management application written in Jac. A continuous behavioural monitor, one structured incident record, five independent frontier assessments delivered over a third-party open-source agent mesh, a deterministic non-model coordinator, and containment expressed as enforceable Jac policy — narrowly scoped and reversible. JacHacks SF 2026.
LIVE — the system is built and has run end to end. Run six-live-e2e: six models across six harnesses, 6 of 6 effort receipts, none blocked, mocked or downgraded. Hermes escalated, five responders assessed independently and returned 5 of 5 malicious (confidence 0.85–0.95), the deterministic coordinator scored 4.54 and chose to contain, and five actions were applied, verified and rolled back — final_state ROLLED_BACK, health pass — while 40 of 40 bystanders in the same tenant kept serving throughout. Narration audio and all seventeen scene visuals are in. A few illustrative panels remain and each is individually labelled ILLUSTRATIVE — anything drawn from the live run is labelled LIVE RUN.
Jac · walkers, nodes, abilities Hermes monitor · z-ai/glm-5.2 5 independent assessments Cotal — third-party open source 817 community security skills containment: scoped + reversible
▶ Narrated walkthrough plays the guided tour — seventeen scenes, about twelve and a half minutes. Or read straight through.
01 · Where this starts

Hugging Face, July 2026 — and the phase that matters is the second one

On 16 July 2026 Hugging Face disclosed a breach of its infrastructure. Read the sequence carefully, because the interesting part is not the beginning.

Primary source · verbatim

Initial access. “A malicious dataset abused two code-execution paths in our dataset processing (a remote-code dataset loader and a template-injection in a dataset configuration) to run code on a processing worker.”

What happened next. “the actor escalated to node-level access, harvested cloud and cluster credentials, and moved laterally into several internal clusters over a weekend.”

Who ran it. “The campaign was run by an autonomous agent framework (appearing to be built on an agentic security-research harness — used LLM still not known)”

Source: Hugging Face security incident disclosure, huggingface.co/blog/security-incident-july-2026, published 16 July 2026. Five days later OpenAI stated the agent was its own: per TechCrunch (21 July 2026), “OpenAI models — including GPT-5.6 Sol and an even more capable pre-release model” executed the breach “while being internally tested on a benchmark of cyber capabilities.” Corroborated the same week by BleepingComputer, CNBC, Axios, Fortune and CNN.

The way in was a vulnerability. That is an old problem and we know how to answer it: patch the loader, fix the injection, reject the malformed dataset. The second phase is the new problem. Once an autonomous agent holds valid cloud and cluster credentials, it stops needing to break anything. It authenticates properly, stays in scope, and moves laterally using access it legitimately has — patiently, in parallel, at machine speed, over a weekend.

02 · The gap

Everything a per-request control can decide — and the one thing it cannot

Phase one — caught, correctly, every time
Each of these is decidable while looking at exactly one request. Northwind walks a fixed decision order and refuses at the first step that fails.
  • Expired or revoked session 401 DENY
  • Token minted for another tenant 403 DENY
  • Role lacks the permission 403 DENY
  • Missing or mismatched CSRF token 403 DENY
  • Malformed body · burst over the route limit 422 / 429
Phase two — allowed, correctly, every time
The campaign. Nothing here is a violation, and a control that refused it would be wrong.
  • Session valid and unexpired 200 OK
  • Correct tenant, every request 200 OK
  • Every scope genuinely held 200 OK
  • CSRF satisfied, headers clean 200 OK
  • Well-formed, under every limit 200 OK
The framing claim of this project

One request at a time, there is nothing to reject. The evidence for the campaign does not exist inside any single request — it only exists across them. So that is where we put the detection.

03 · Shared security knowledge

A community cybersecurity skills library — vendored, pinned, credited

The responders do not improvise security expertise. They load it. Vendored into this repository at vendor/cybersecurity-skills, pinned to a single commit, is an open-source library of 817 cybersecurity skills under Apache-2.0, from github.com/mukul975/Anthropic-Cybersecurity-Skills. VENDORED — REAL IN THE REPO

Attribution — read this one carefully

The repository is community-maintained. Despite the name, it is not an official Anthropic release and we do not present it as one. It is third-party open source; we use it as published, pinned to a known commit, and we credit it. We did not write it.

Every assessment a responder returns carries a skills_used[] list — the path and content hash of each skill it actually loaded. Five models reason from one shared body of practice, and you can check afterwards which parts of it each one used.

04 · Coordination layer

Cotal — an open-source NATS agent mesh we depend on

Attribution

Cotal is third-party open source. We did not author it. We use it as a dependency, as published, and we credit the project.

MULTICAST
channel — the incident is published once, to everyone who should see it
ANYCAST
toService — one of a pool takes the work
UNICAST DM
to — a direct message to exactly one recipient

The design turns on the last one. The incident goes out on a channel; every assessment comes back by direct message. A responder is not merely asked to ignore its peers — it mechanically cannot see them. Independence is enforced by the transport, not by good manners.

05 · The thesis

Stated exactly as we would defend it

Traditional controls can reject invalid requests, but a stolen valid credential operated by an autonomous agent may look normal one request at a time. Our system recognizes the coordinated behavior, assembles five independent model assessments, and applies narrowly scoped containment through enforceable Jac policy.
COMMITMENT 1
Detect the pattern, not the request
COMMITMENT 2
Decide with five models — none of which decides alone
COMMITMENT 3
Contain narrowly, through enforceable policy
COMMITMENT 4
Prove it and reverse it
06 · The target

Northwind Projects — an ordinary, correctly secured multi-tenant SaaS in Jac

The single most important framing on this page

This application is not deliberately vulnerable. Nothing was weakened to make the demo work. Every control below is the control you would actually ship. If we had removed one, the demo would prove nothing — the whole point is that a correctly secured application, behaving exactly as designed, still answers an agent holding a valid credential.

SESSION
__Host-sid cookies, expiry and revocation
CSRF
__Host-csrf double-submit on every mutation
TOKENS
nwp_ bearer tokens, argon2id-hashed at rest
AUTHZ
A fixed 15-step deny decision order per request
TENANCY
Per-(user, tenant) membership: owner > admin > member > viewer
RATE
Per-route rate limits
EDGE
Restrictive CORS · HSTS · CSP · full header set
DOMAIN
Tenant → Project → Task → Comment · sensitivity normal | confidential | canary

GATEWAY AND DOMAIN WALKERS — IMPLEMENTED AND SERVING The API contract is frozen and the application serves it. In run six-live-e2e the containment health probes were answered by this gateway and its domain walkers — allow and deny decisions taken live, not simulated.

07 · End to end

Detection, judgment and enforcement are three separate things

The application
Northwind Projects · Jac
normally secured · emits behavioural windows — counts and rates per actor, never bodies or content
▼
Continuous monitor
Hermes · z-ai/glm-5.2
always on, deliberately cheap · its only write capability is publishing one incident
▼
Correlation
The incident record
join keys · evidence event ids · signal families · campaign stage signatures
▼
⇆  Cotal mesh — one incident out on a channel, five assessments back by direct message  ⇆
▼
Claude Code
Claude Opus 5
Codex
GPT-5.6 Sol
Antigravity
Gemini 3.6 Flash
OpenCode
Kimi K3
OpenCode
GLM-5.2
▼
Not a model — explicitly not an LLM judge
Deterministic coordinator · plain Jac
fixed rule, fixed inputs, same answer every time · records whether it ran degraded
▼
The only thing allowed to act
Containment · enforceable Jac policy
scoped to a principal, session, token, source or feature — never a whole tenant
The record
Audit trail & rollback
prior state snapshotted with every action · TTL expiry · rolled_back is a state, not an incident
08 · The always-on layer

Hermes watches shape, never content

Hermes runs on z-ai/glm-5.2 and is deliberately the cheapest component in the system, because it is the only part that never stops. It reads 15-second tumbling windows, keeps a rolling 90 seconds, and compares each actor against its own recent p95 baseline. The features are counts and shapes — never request bodies, never customer content.

VOLUME
req · distinct_paths
SPREAD
path_entropy · new_endpoints_first_seen
REFUSALS
auth_fail · authz_deny · deny_ratio
PIVOT
post_deny_pivot_ms_p50 — how fast it moves on after a refusal
ORIGIN
src_ips_distinct · ua_distinct
BOUNDARY
cross_tenant_attempts
BAIT
canary_touch — resources that exist only to be touched by mistake
EGRESS
integration_calls · export_bytes

None of those is a violation, and each has an innocent explanation. Hermes is not deciding guilt — it decides whether something deserves a real look. That is the only judgment it is trusted with, and publishing the incident is the only thing it is permitted to write. DETECTOR IMPLEMENTED — RAN LIVE ON z-ai/glm-5.2 AT EFFORT xhigh

09 · Five independent assessments

Five models, five harnesses, one incident

Claude Opus 5
Claude Code
anthropic/claude-opus-5 · max
GPT-5.6 Sol
Codex
openai/gpt-5.6-sol · max
Gemini 3.6 Flash
Antigravity
google/gemini-3.6-flash-high · high
Kimi K3
OpenCode
moonshotai/kimi-k3 · max
GLM-5.2
OpenCode
z-ai/glm-5.2 · max
The same structured answer, from all five

A verdict — malicious, suspicious or benign. A confidence. The campaign stages it believes it is seeing. The containment actions it recommends, and against what target. The skills it loaded. And a rationale capped at 400 characters, so nobody can hide a weak argument inside a long one. Five different training lineages, identical evidence, each answering alone.

ALL FIVE HARNESSES RAN LIVE — six-live-e2e · 6/6 EFFORT RECEIPTS · NONE DOWNGRADED, MOCKED OR BLOCKED NARRATION PREDATES THE MODEL PIN — the recorded line says “Gemini 3.1 Pro”; the run used google/gemini-3.6-flash-high, shown above.

10 · The decision

Then we stop using models

The coordinator is not a sixth opinion and it is explicitly not an LLM judge — it is plain Jac, with no model behind it at all, running a fixed rule over the five assessments.

contain iff >= 3/5 malicious AND score >= 1.5
Responder
Confidence
Verdict
Weight
Claude Opus 5 0.85
MALICIOUS
?
GPT-5.6 Sol 0.94
MALICIOUS
?
Gemini 3.6 Flash 0.95
MALICIOUS
?
Kimi K3 0.90
MALICIOUS
?
GLM-5.2 0.90
MALICIOUS
?
5 of 5 malicious · score 4.54 · quorum met · not degraded · contain LIVE RUN six-live-e2e — REAL VERDICTS AND CONFIDENCES PER-RESPONDER WEIGHTS STILL NOT FIXED

It records how many voted each way, whether quorum was actually met, and whether the decision ran degraded because a responder timed out. A split does not get resolved by guessing: it triggers one bounded round of deliberation, and if it still will not settle, a human gets it.

The open number — stated, not invented

The vote rule and its threshold are frozen in the contract. The per-responder weights and the exact score formula are the one thing in this design we have not fixed yet. We would rather say so than put a made-up number on a slide.

11 · Containment

Containment is data before it is action

Every proposal is a containment-action node and every enforcement is a control node, so what was decided and what was applied are separately recorded. There are ten kinds, and each ships with a default blast radius, a default time to live, and whether a human has to approve it. JAC DATA MODEL — WRITTEN AND COMPILING

revoke_sessionend one session; the identity survives
CHOSEN
revoke_tokenburn one bearer token
CHOSEN
suspend_principalttl 1800s
REVERSIBLE
force_reauthttl 3600s
REVERSIBLE
throttle_sourcettl 900s
REVERSIBLE
block_sourcettl 900s
REVERSIBLE
feature_readonlyttl 900s
REVERSIBLE
pause_queuettl 600s
REVERSIBLE
raise_loggingttl 3600s
REVERSIBLE
rotate_service_credentialnever automatic
HUMAN REQUIRED
Two rules govern every action

Scope. A target is a principal, a session, a token, a source address, a feature flag, a queue, a credential or an integration. Never a whole tenant, and never the service.
Reversal. Every action snapshots the prior state before it changes anything, carries a TTL that expires it automatically, and has rolled_back as an ordinary recorded state — so undoing it is a routine operation, not an emergency. EXECUTOR IMPLEMENTED — 5 ACTIONS APPLIED, VERIFIED AND ROLLED BACK LIVE · final_state ROLLED_BACK · health pass

The run

Eight beats, in order

1 · CONTROLS
Invalid requests rejected, correctly
2 · CAMPAIGN
Valid credential · every request legitimate
3 · CORRELATE
One incident record, with its evidence
4 · ESCALATE
Hermes publishes it to the mesh
5 · RESPOND
Five assessments, by direct message
6 · DECIDE
Deterministic rule, no model
7 · CONTAIN
Scoped action · legitimate traffic continues
8 · ROLLBACK
Full audit trail · reversal proven

THIS BUTTON ONLY ANIMATES THE BEAT SEQUENCE — the real execution is run six-live-e2e

Beat 1 · The boring half

Ordinary controls, doing their job

10:04:11GET/t/acme/projects — session expired 40m ago401
10:04:12GET/t/globex/projects — token minted for tenant acme403
10:04:13DELETE/t/acme/projects/18 — role viewer, delete not held403
10:04:14POST/t/acme/tasks — __Host-csrf missing on a mutation403
10:04:15POST/t/acme/tasks — body fails schema, title 12kB422
10:04:15GET/t/acme/tasks — 240 requests in 10s, one session429
— fixed decision order, refuse at the first failing step. every one of these is decidable from a single request. —

Hold on to how clean this looks. The next log looks exactly as clean — and it is the attack. LOG ILLUSTRATIVE

Beat 2 · The attack

A valid credential, and not one refusable request

Same application. Same controls. A genuinely valid credential belonging to a synthetic identity compromised for this demo. Watch the status codes.

10:11:02GET/t/acme/projects/4/tasks — authenticated, in tenant, in scope200
10:11:02GET/t/acme/projects/17/tasks — authenticated, in scope200
10:11:03GET/t/acme/projects/23/comments — authenticated, in scope200
10:11:03GET/t/acme/projects/31/tasks — authenticated, in scope200
10:11:04GET/t/acme/projects/9/comments — authenticated, in scope200
10:11:04GET/t/acme/projects/44/tasks — authenticated, in scope200
— read one line: nothing to report. read the window: 31 unrelated projects in 94 seconds, from one actor. —

The anomaly does not exist in a row. It exists in the window. LOG ILLUSTRATIVE

Beat 3 · Correlation

One incident record — joined, evidenced, and named

The requests stop being log rows and become a single incident: joined on the principal, the tenant, the session identifiers, the source addresses and the user agents, carrying the list of event ids that make up its evidence. On top of that join the incident names what it is seeing — and the campaign stages those signals imply.

NORMAL ACTOR — narrow, deep P one project · its tasks · their comments CAMPAIGN — wide, flat, unrelated P 31 unrelated projects · one principal · 94 seconds every edge individually authorized
authorized access — ordinary work authorized access — campaign fan-out DRAWN BY HAND — REPLACED BY A CAPTURE OF THE LIVE INCIDENT RECORD
BREADTH
how much of the tenant one actor reached
NOVELTY
endpoints this identity had never touched
CADENCE
a rhythm no person types
PIVOT
how fast it moves on after a refusal
DENIAL SHAPE
the pattern of what it was refused
ESCALATION
reaching for more than it started with
CANARY
resources that exist only to be touched by mistake
STAGES
the campaign stage signature those signals imply

That is the artifact the responders receive — not a log excerpt, and not a paragraph we wrote for them. A structured incident record with its evidence attached, that any of the five can walk for itself.

Beats 4 & 5 · Escalation and response

One incident out, five assessments back

HERMES
Publishes the incident — the only write it is allowed
COTAL
One channel out; no path between the five responders
SKILLS
Each loads the skills it thinks the case needs, and reports which
RETURN
Verdict · confidence · stages · recommended actions · rationale
— the response window: one publish out, five direct messages back, no path between them —
PUBhermes → incident · one principal, 94s window, evidence attachedOPEN
DMClaude Opus 5 · Claude Code — assessment returnedIN
DMGLM-5.2 · OpenCode — assessment returnedIN
DMGPT-5.6 Sol · Codex — assessment returnedIN
DMGemini 3.6 Flash · Antigravity — assessment returnedIN
DMKimi K3 · OpenCode — assessment returnedIN
— five assessments in, each written without sight of the other four. the counts are on the decision panel. —

What we refuse to do is let the first confident answer become the decision. ALL FIVE ASSESSMENTS ARE LIVE AND UNEDITED — runs/six-live-e2e/assessments/ NARRATION PREDATES THIS RUN — the recorded line describes a four/one split. On six-live-e2e all five returned malicious (0.85–0.95). The point it makes still holds: no responder can see another's answer, so agreement is a result, not a shared prior.

Beats 6 & 7 · Action, and the half usually skipped

Narrow containment — while everyone else keeps working

What policy did
The five narrow actions the coordinator decided, each applied and verified.
  • revoke_session sess_anon_5b31… CONTAINED
  • revoke_session sess_c9f4a1b2… CONTAINED
  • suspend_principal c_32bfd983… CONTAINED
  • force_reauth · raise_logging APPLIED
  • Tenant t_acme not locked · service availability UNTOUCHED
The other lane — same tenant, same second
40 of 40 bystanders in t_acme kept serving while containment was in force — 0 denied. A representative sample:
  • u-mara POST /t/acme/tasks 200 OK
  • u-devon GET /t/acme/projects/4 200 OK
  • u-priya POST /t/acme/comments 200 OK
  • u-sam GET /t/acme/projects/9/tasks 200 OK
  • u-mara PATCH /t/acme/tasks/311 200 OK
The claim this beat exists to prove

No service shutdown. No tenant lock. No mass sign-out. And the prior state was snapshotted before anything changed, so the reversal already exists at the moment the action does. Containment that stops the business is not containment — it is a slower outage. LIVE RUN — 40/40 BYSTANDERS SERVING, 0 DENIED · CONTAINED SUBJECT BLOCKED SAMPLE USER ROWS ILLUSTRATIVE

Beat 8 · Proof and reversal

Everything on the record — and undone in one recorded operation

Record
Contents
Replayable
window
the behavioural window Hermes acted on, verbatim
yes
incident
join keys, evidence event ids, families, stage signature
yes
assessments
all five verdicts, confidences, rationales and skills used — unedited
yes
decision
verdict counts, quorum met, degraded flag, the computed score
yes
action
the containment kind, its target, its TTL, and the prior state it snapshotted
yes
rollback
state → rolled_back · session restored · recorded like any other operation
yes
The argument, in full

Recognise behaviour instead of requests. Decide with five independent models and a rule that is not a model. Contain narrowly, prove it, and reverse it. LIVE RUN six-live-e2e — ALL SIX RECORDS WRITTEN · control_surface_after_rollback: []

Honesty panel

What this page is, right now

Real today
  • One live end-to-end run, six-live-e2e, on six models across six harnesses — 6/6 effort receipts, none blocked, mocked or downgraded.
  • Five independent assessments, unedited on disk: 5/5 malicious, confidence 0.85–0.95. All five named campaign stages 2, 3 and 4; Claude and Kimi independently added stage 6. Four of the five explicitly flag the planted prompt injection in the untrusted evidence.
  • The deterministic coordinator: score 4.54, quorum met, not degraded, contain: true — plain Jac, no model.
  • The containment executor: five actions applied, verified and rolled back, control_surface_after_rollback: [], final_state ROLLED_BACK, health pass.
  • The Northwind gateway, domain walkers and Hermes detector — running, and the source of the live allow/deny probes. 40 of 40 bystanders kept serving during containment.
  • The vendored skills library, pinned to a commit, 817 skills. The full walkthrough: seventeen scenes, all voiced, all visuals in.
Still illustrative — and labelled as such
  • The two request logs in beats 1 and 2, and the sample user rows in beat 7. The run they depict is real; those particular rows are hand-written.
  • The incident-graph drawing — still hand-drawn, not a capture of the live incident record.
  • The per-responder weights and the exact score formula — the one number in this design we have not fixed. The narration says so out loud, and we would rather say so than invent one.
  • The ▶ button on the demo tab animates the eight beats; it is a scripted preview of the sequence, not a re-execution.
  • Two recorded narration lines predate the live run — the four/one split in scene 15 and “Gemini 3.1 Pro” in scene 9. Both are corrected on screen where they occur.
Attribution. Cotal is third-party open source; we use it as a dependency and did not author it. The cybersecurity skills library mukul975/Anthropic-Cybersecurity-Skills (817 skills, Apache-2.0) is community-maintained and is not an official Anthropic release.
Sources for scene 1 — Hugging Face security incident disclosure, 16 July 2026; TechCrunch, 21 July 2026; corroborated by BleepingComputer, CNBC, Axios, Fortune and CNN. Re-check before presenting: the story is days old.
JacHacks SF 2026 · walkthrough frame · no credentials or environment values appear anywhere in this artifact.
build dev · frame-only · audio 17/17 · no captures