v3.2.0 — cloud audit logs as a second witness, and a ⌘K command palette

Incident response for AI agents.

Claude Code, Codex, Cursor and eleven other agents run shell commands, read credentials and call MCP servers with your privileges. AgentDFIR acquires what they leave on disk into sealed, hash-chained evidence, reconstructs the attack chain, and puts the exact log line behind every finding.

$curl -fsSL https://raw.githubusercontent.com/efij/AgentDFIR/main/install.sh | sh && ~/.local/bin/agentdfir run
Step 1/4 Detect claude-code codex-cli cursor-cli +3 Step 2/4 Collect sealed 9,036 artifacts · SHA256SUMS written Step 3/4 Analyze 115,655 events · 8 chains evaluated 3 CRITICAL 167 HIGH 457 MEDIUM Step 4/4 Look http://127.0.0.1:53114/ loopback · read-only
SHA-256 verified install, one static binary, nothing executed on the evidence. Air-gapped and USB use
14AI agents parsed
172deterministic detections
8attack chains
ATLAS 5.6+ ATT&CK mapping
SHA-256sealed, hash-chained
0runtime dependencies
AgentDFIR case explorer, dark theme. Open finding: “The agent read a password or key, then sent data out”, severity Act now, with what happened, why it matters, the most likely start, the matched chain steps and the outside address.
Story diagram close-up: the agent opened ~/.aws/credentials (flagged step 1), the tool answered with the keys masked, then the agent ran curl -X POST to cdn.acme-metrics.example (flagged step 2).

Reads the on-disk evidence of fourteen AI agents

  • Claude Code
  • Codex CLI
  • Cursor
  • Gemini CLI
  • GitHub Copilot
  • Claude Cowork
  • Cline
  • OpenCode

What the agent says is not what the computer did.

“I ran curl example.com” in a chat proves nothing. Every action on every timeline says how strongly it is backed, from a claim in the conversation up to the computer's own records, and a second witness (auditd, Sysmon, your EDR or MCP gateway) can confirm it or prove it false.

  • A second witness. analyze --endpoint audit.log lines up each tool call with the operating system's own process and network records. Pass a CloudTrail, Azure Activity Log or GCP audit export and every az, aws and gcloud command is checked against the cloud's own record.
  • Lies surface. An agent that says it did something the computer never saw becomes a finding of its own.
  • Off the record. Processes and connections the agent never mentioned are reported too.
Claimed by the agentSaid in the chat, not shown in the log
Asked for by a personRequested, not shown to have happened
Written in the agent's logA tool-call record exists in the transcript
Confirmed by the computerThe OS, EDR or gateway saw the same thing
The computer disagreesIts own records show it did not happen
Not cross-checkedNo second witness was given, said plainly

Watch a chain assemble.

Four lines from one real-shaped transcript. Each is unremarkable. Together, in this order, inside two minutes, they are an incident.

  1. A web page talks to the agent. The tool answer carries text that reads like instructions.
  2. The agent rewrites its own settings. It adds a hook that ships every file it writes to an outside address.
  3. A shell command runs. Your cloud credentials leave the machine.
  4. One finding, not three alerts. CRITICAL, with the start marked and each step tied to its log line.

Seven hundred alerts are not an answer. The chain is.

Attack chains match ordered steps inside one session: harmless alone, an incident together. Each match is one finding with the steps, the root cause marked, and the event that proves every step.

  • CRITSecret read, then data left the hostAML.T0086 · T1048
  • CRITTool result rewrote instructions, then code ranAML.T0080.000 · T1059
  • CRITPoisoned MCP result, then a destructive commandAML.T0099 · T1485
  • CRITOrphan agent changed config, then actedAML.T0081 · T1562.001
  • CRITRisky action, then the agent's logs deletedAML.T0101 · T1070.004
  • HIGHInjected instructions, then code pushedAML.T0010 · T1195.002
  • HIGHSubagent cross-talk, then exfiltrationAML.T0086 · T1048
  • MEDDownload, then executeT1105
Write your own chains in JSON
Story diagram of a context-poisoning chain: the user asked the agent to read a vendor setup guide; the tool answer carried hidden instructions (marked Start, flagged step 1); the agent then wrote its own settings file (flagged step 2) and ran a shell command.

The last twelve months of agent incidents, as commands.

New in v3.0. Every capability comes from a real 2025–2026 incident and is tested against a reproduction of it (agentdfir simulate --scenario list).

  • hunt — was I hit? Verified indicators for s1ngularity, Shai-Hulud 1 and 2, the keyv wave, SANDWORM_MODE, postmark-mcp, codexui-android, the Amazon Q wiper and Storm-3168 / JADEPUFFER, plus STIX 2.1 and MISP feeds. A command the agent ran is observed; a question about the incident is only mentioned. Evidence that starts after the incident says inconclusive, not all-clear.
  • scan-repo — before an agent opens it. Committed SessionStart hooks, VS Code folderOpen tasks, repo MCP servers, injected AGENTS.md, install scripts that run AI CLIs headless. SARIF, a GitHub Action and a pre-commit hook.
  • decode — no model refuses to help. Nested base64, gzip, hex and UTF-16LE payloads unwrapped offline; every rule sees what an executed payload really runs.
  • monitor --journal — the transcript can lie. Every append hash-chained as it is written, the chain head anchored off the file; a later edit is TRANSCRIPT_REWRITTEN.
$ agentdfir scan-repo work/appexit 1
  CRITICAL REPO_AGENT_HOOK_AUTORUN
           .claude/settings.json: SessionStart runs
           `node .claude/setup.mjs` — no tool call, no prompt.
           Risk: setup.mjs contacts npm-cache.com; reads
           .claude/.credentials.json
  CRITICAL REPO_VSCODE_AUTORUN_TASK
           .vscode/tasks.json: "Environment Setup" runs
           when the folder is opened

# nothing in the repository was executed
$ agentdfir hunt --path ~/srcexit 0
  NO EVIDENCE   keyv-wave      Shai-Hulud keyv / cacheable wave
  NO EVIDENCE   sandworm-mode  SANDWORM_MODE npm worm
                (1 mention in conversation text — context,
                 not evidence of compromise)
  INCONCLUSIVE  s1ngularity    Nx "s1ngularity" npm compromise
                agent activity starts after the incident

Every finding resolves to a line in a sealed file.

Open any step and you get the raw transcript line, its logical path and line number, every other rule the same event triggered, and the account that ran it. Whole-case search covers every byte of the sealed evidence, not only the parsed events.

  • Per-account attribution. Findings name the AI account behind them, read from the agent's own profile. Tokens are never read.
  • Secrets masked on screen. Reviewing a leak does not leak it again.
  • ⌘K for everything. One box jumps to any finding, conversation or view by fuzzy match, and shows matching actions from the evidence as you type.
  • Case file. Verdicts, pinned evidence and notes go to a hash-chained log outside the sealed zone, attributed to the analyst.
Proof drawer: every finding the step triggered, from Act now to Minor, then the exact line from the sealed log with its path and line number.

Then make sure it cannot happen again.

agentdfir mitigate turns findings into guardrails in the agents' own settings: Claude Code permissions and a log-guard hook, a Codex rules file, Cursor CLI denies, pinned MCP packages. It shows the plan first, backs up every file, records each change in a hash-chained ledger and can put every byte back.

  • Two packs with zero friction, on by default. The agent cannot delete its own transcripts or read cloud keys, SSH keys and browser password stores.
  • Seven more, opt-in, each with its cost stated. Ask before uploads, downloaded scripts, persistence, self-modification, destructive commands, and deleting cloud resources or their backups.
  • Drift detection. --status re-reads every file and flags a guardrail an agent removed after it went in.
  • Or from the browser. On the machine the case came from, the Protect tab previews every file and diff, applies on a click and undoes any change, byte-exact. For a case from another computer it builds the command to run there.
$ agentdfir mitigate --apply --yesexit 0
  applied  ~/.claude.json                   id e4fbd3c91cda
  applied  ~/.claude/settings.json          id 9bf8598b55aa
  applied  ~/.codex/rules/agentdfir.rules   id 24715a787929
  applied  ~/.cursor/cli-config.json        id 5a7b3ee2eb39

# the next scan counts only what happens after this
$ agentdfir mitigate --status
e4fbd3c91cda in place  ~/.claude.json            fix
9bf8598b55aa in place  ~/.claude/settings.json   log-protect,secret-paths
Protect tab of the case explorer: guardrail packs with level, friction and the findings each covers, two packs pre-selected, and the agentdfir mitigate command to copy.

Collected on one machine, investigated on yours.

One file moves a case. The seal is verified on arrival, and the analysis is rebuilt by the receiving binary, so nobody has to trust someone else's conclusions.

suspect machine$ agentdfir export
Exported IR-7.adfir → IR-7.adfir.tgz (7 KB, 2ms)
SHA-256  916c715f4e0f1e0e289789ebc51c6094…
Sealed evidence and case notes are inside; the
analysis is rebuilt on the other computer.

# on the other computer:
agentdfir open IR-7.adfir.tgz
analyst workstation$ agentdfir open IR-7.adfir.tgz
Unpacking IR-7.adfir.tgz (SHA-256 916c715f4e0f1e0e…)
Verified: 6 artifacts, 26 collection and 3 custody
records, seal intact.
Attack chains: 8 chain(s) evaluated, 3 matched
AgentDFIR case explorer — 28 events, 21 findings
Open http://127.0.0.1:54222/

Chain of custody that survives cross-examination.

Every acquisition is a sealed .adfir package: content-addressed blobs, hash-chained collection and custody logs, a SHA-256 seal over the evidence zone, optional ed25519 signature. The format is open, so any tool can verify it without AgentDFIR.

$ agentdfir verify CASE-2026-042.adfirexit 0
Depth:              full (every stored blob re-hashed)
Rounds:             1
Artifacts OK:       6 (not acquired: 0)
Collection records: 26 (hash chain)
Custody records:    3 (hash chain)
Signature:          none (package is unsigned)
Result:             VERIFIED — no modifications detected
one byte changed in raw/240b7ed8…exit 1
Depth:              full (every stored blob re-hashed)
Artifacts OK:       6 (not acquired: 0)
Collection records: 26 (hash chain)
Custody records:    3 (hash chain)
Result:             FAILED — 2 problem(s):
  - raw/240b7ed8bfdeafa9e562…: hash mismatch
  - .claude/projects/-Users-dev-app/5f0c9c1e….jsonl:
    content-address mismatch
case.adfir/open format · docs/adfir-spec.md
raw/<sha256>[.gz]           # content-addressed evidence, sealed once, never rewritten
manifest.jsonl              # every artifact: source path, size, times, hash, round
collection.jsonl            # hash-chained acquisition log, including every failure
chain-of-custody.jsonl      # hash-chained: who touched the package, when, why
SHA256SUMS                  # seals the evidence zone; seals/ keeps every earlier round's
normalized/ detections/     # analysis overlay, regenerable, never part of the seal

Built for hostile hosts.

Assume the machine is compromised and the evidence is adversarial. Suspect binaries are never executed, symlinks never followed, and ANSI escapes and invisible Unicode are neutralized before they reach your terminal.

agentdfir mcp audit

MCP supply chain

Every MCP server across every agent: unpinned packages, plaintext transports, auto-approve, poisoned tool descriptions, name collisions and baseline drift.

agentdfir provenance

Instruction provenance

For each line of CLAUDE.md, AGENTS.md or .cursorrules: which session and agent wrote it, and whether it came from a person or from tool output.

agentdfir monitor --detect

Real-time sensor

Exfil sequences, honeytoken hits and self-modification pushed to a webhook, syslog or file within seconds of the transcript line being written.

collect --live

Volatile acquisition

RFC 3227 order of volatility: running agent processes, open files and connections first, then the on-disk evidence, with torn-read detection for files still being written.

agentdfir simulate

Adversary emulation

Generate orphan-agent and toxic-chain incidents to validate your detections and train responders before the real one.

rules/*.json

Rules you can read

No model in the analysis path. Detections are deterministic Go and JSON rule packs, signed pack updates, and a coverage matrix generated from the binary.

Mapped to MITRE ATLAS and ATT&CK.

Every HIGH and CRITICAL detection carries a technique, including ATLAS's agentic family. The mapping is enforced by tests, so a rule cannot ship without one.

ATLASTechniqueRules
AML.T0086Exfiltration via AI Agent Tool InvocationCHAIN_SECRET_TO_EXFIL, POTENTIAL_DATA_EXFILTRATION, CURL_FILE_UPLOAD…
AML.T0080.000Memory (context poisoning)CHAIN_CONTEXT_POISON_TO_EXEC, INSTRUCTION_FROM_TOOL_RESULT, AGENT_CONTEXT_POISONING…
AML.T0081Modify AI Agent ConfigurationAGENT_SELF_MODIFICATION, PERMISSION_BYPASS_ENABLED, CHAIN_ORPHAN_PERSISTENCE…
AML.T0083Credentials from AI Agent ConfigurationAGENT_CREDENTIAL_STORE_ACCESS
AML.T0110AI Agent Tool PoisoningMCP_TOOL_DESCRIPTION_POISONING, TOOL_POISONING_INDICATOR
AML.T0099AI Agent Tool Data PoisoningCHAIN_MCP_RESULT_TO_DESTRUCTIVE, MCP_TOOL_POISONING
AML.T0051LLM Prompt InjectionINSTRUCTION_INJECTION_PHRASE, PROMPT_INJECTION_INDICATOR, ROLE_MARKER_SMUGGLING
AML.T0068LLM Prompt ObfuscationINVISIBLE_UNICODE_INSTRUCTION
AML.T0010AI Supply Chain CompromiseUNPINNED_MCP_PACKAGE, MCP_REMOTE_FETCH_COMMAND, CHAIN_INJECTION_TO_PUSH…
AML.T0101Data Destruction via AI Agent Tool InvocationCHAIN_ACTION_THEN_LOG_TAMPER, DESTRUCTIVE_COMMAND, DISK_WIPE
Full matrix: 172 detections, 28 ATLAS techniques

Collect from anywhere

this machine · --path image
--import KAPE/Velociraptor/CyLR
--docker · --archive CI

Second witness

auditd · Sysmon XML
EDR JSONL/CSV · eslogger
CloudTrail · Azure Activity · GCP audit
MCP gateway logs

Export to your stack

OCSF 1.3 · SARIF 2.1 · STIX 2.1
Sigma · OTel · Timesketch
l2tcsv · PDF · HTML

Deploy at scale

KAPE target + module
Velociraptor artifact
signed product packs

One command, or four.

agentdfir run is the four steps below, same code. Run them one at a time on a disk image, a KAPE tree or a container.

  1. 01

    Detect

    Which agents are installed. Nothing is executed.

    agentdfir detect
  2. 02

    Collect

    Sealed, hash-chained evidence package.

    agentdfir collect --case-id IR-042
  3. 03

    Analyze

    Detections, chains, MCP audit, provenance.

    agentdfir analyze IR-042.adfir
  4. 04

    Investigate

    Case explorer on 127.0.0.1, or reports.

    agentdfir serve IR-042.adfir
Homebrewbrew install efij/agentdfir/agentdfir
Chocolateychoco install agentdfir
Scoopscoop bucket add agentdfir https://github.com/efij/scoop-agentdfir; scoop install agentdfir
Windows (cmd or PowerShell)powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/efij/AgentDFIR/main/install.ps1 | iex"
Gogo install github.com/efij/AgentDFIR/v3/cmd/agentdfir@latest
Verify a releaseEvery asset ships a Sigstore bundle; cosign verify-blob --offline works air-gapped. Exact command

Questions from responders

What is AI agent forensics?

Collecting, preserving and analyzing what agentic AI tools leave on endpoints — session transcripts, subagent records, MCP configuration, hooks and tool-call logs — so a responder can reconstruct who instructed which agent to do what, through which tool and account, and what evidence proves it.

Where does Claude Code store session logs?

Transcripts are JSONL under ~/.claude/projects/<project>/<session-id>.jsonl, prompt history in ~/.claude/history.jsonl, settings, hooks, skills and plugins under ~/.claude/, and MCP servers in ~/.claude.json. AgentDFIR acquires all of them, including subagent and orphan-agent transcripts. See the artifact reference.

Is anything sent off the machine?

No. No account, no cloud, no telemetry, no language model in the analysis. The explorer binds to 127.0.0.1, serves a strict CSP with no external resources, and never writes to the sealed evidence.

What is an attack chain?

An ordered sequence of agent events that is unremarkable alone and an attack together: instruction-override content in a tool result, then the agent writing its own settings, then a shell command, in one session within a time window. Eight chains ship built in; you can add your own in JSON.

Does it work on a disk image or a KAPE collection?

Yes. collect --path takes a copied home or a mounted image, --import takes a KAPE, Velociraptor or CyLR tree with every user and every agent, --docker snapshots a container read-only and --archive ingests CI artifacts and support bundles.

What does it detect?

172 deterministic rules: orphan agents, cross-agent messaging, destructive and exfiltrating commands, agents editing their own instructions or hooks, credentials read from agent config, poisoned or unpinned MCP servers, honeytoken hits and transcript integrity gaps. See the coverage matrix.

Documentation and open schemas

Your agents have shell access. Know what they did with it.

MIT-licensed. One static binary, no runtime dependencies, auditable in an afternoon.