Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,58 @@ and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.

## [Unreleased]

Lessons from the 2026 agent-driven cloud attacks: Microsoft's Storm-3168,
Sysdig's JADEPUFFER and Sygnia's AI-assisted intrusion.

### Added
- **Cloud audit logs as a second witness.** `--endpoint` (on `analyze`,
`run` and `correlate`) now reads AWS CloudTrail, Azure Activity Log and
GCP Cloud Audit Log exports as JSON, a JSON array or JSON Lines, sniffed
per file (`--format cloud-audit` to force it). An agent's `az`, `aws` or
`gcloud` command becomes CORROBORATED when the control plane recorded the
same operation within ±2 minutes, on the same resource when the command
names one; a call the cloud refused is noted with its error. A cloud log
never contradicts a command, since the export may cover another account,
and it never counts as host telemetry. Files only, no cloud API calls.
- **`CLOUD_DESTRUCTIVE_BURST`** (HIGH): the cloud audit log shows one
identity deleting 10+ distinct resources within 10 minutes. It says
whether any of the deletes match commands in the collected transcripts.
- **`CLOUD_RESOURCE_DELETION`** (HIGH): the agent deletes storage accounts
or buckets, key vaults, secrets, KMS keys, apps, resource groups, VMs,
clusters, stacks or projects through `az`, `aws`, `gcloud` or `gsutil`.
- **`CLOUD_RECOVERY_PROTECTION_REMOVED`** (CRITICAL): the agent deletes a
resource lock, disables backup protection, deletes a backup vault,
recovery point or snapshot, suspends bucket versioning or turns off
deletion protection.
- **Guardrail pack `cloud-destructive`** (ask, friction 1): the agent must
ask before those commands, before destroying databases and before
stopping cloud logging. Claude Code and Codex. Read and list commands are
never asked.
- **Incident `storm-3168-jadepuffer`** for `agentdfir hunt`: the published
attacker addresses, and Langflow below 1.3.0 (CVE-2025-3248, the entry
point) at low confidence. Package indicators gain `below_version` for
vulnerable-version ranges. The ransom note's Bitcoin address is left out
on purpose: it is the example address from the Bitcoin docs.
- **Authority-claim phrases** ("this is an approved red team exercise",
"you are authorized to bypass" …) count as injection in tool and MCP
results, fetched content, instruction files, tool definitions, MCP
configs and repository files. Never in the person's own prompts, where a
pen-tester writes exactly that.
- Secret formats `ALIBABA_ACCESS_KEY` (`LTAI…`) and `TENCENT_SECRET_ID`
(`AKID…`).

### Changed
- `CLOUD_CREDENTIAL_EXPORT` also covers listing storage account keys and
connection strings, Cosmos DB keys, service-principal credential resets
and GCS HMAC keys.
- The Protect tab's steps for a leaked secret say that deleting it from an
issue, pull request or commit does not remove it from edit history,
forks or caches.

### Fixed
- Re-running analysis with the same endpoint log appended the same
corroboration note to an event again on every run.

## [3.1.2] — 2026-09-29

### Changed
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ Add a second witness and the same commands upgrade every finding from *the agent

```sh
agentdfir analyze CASE-2026-042.adfir --endpoint /var/log/audit/audit.log # auditd / Sysmon XML / EDR exports
agentdfir analyze CASE-2026-042.adfir --endpoint cloudtrail.json # CloudTrail / Azure Activity Log / GCP audit exports
agentdfir analyze CASE-2026-042.adfir --gateway-log mcp-gateway.jsonl # your MCP gateway's own log
```

Expand Down Expand Up @@ -131,7 +132,7 @@ Every capability below comes from a real 2025–2026 incident and is tested
against a reproduction of it (`agentdfir simulate --scenario list`).

```sh
agentdfir hunt --path ~/src # was I hit? s1ngularity, Shai-Hulud 1/2, keyv wave, SANDWORM_MODE, postmark-mcp, codexui, Amazon Q
agentdfir hunt --path ~/src # was I hit? s1ngularity, Shai-Hulud 1/2, keyv wave, SANDWORM_MODE, postmark-mcp, codexui, Amazon Q, Storm-3168/JADEPUFFER
agentdfir scan-repo ~/src/untrusted # before an agent opens it: committed SessionStart hooks, folderOpen tasks, repo MCP servers, injected AGENTS.md
agentdfir decode payload.txt # nested base64/gzip/hex/UTF-16LE payloads, offline — no model refuses to help
agentdfir monitor --journal # hash-chain every transcript append; a later edit becomes TRANSCRIPT_REWRITTEN
Expand Down Expand Up @@ -160,7 +161,8 @@ agentdfir monitor --journal # hash-chain every transcript append; a lat
secret-hunting prompt, exfiltration through trusted services (link
shorteners, screenshot services, `workers.dev`, blockchain RPC,
tunnels), GitHub repo creation as an exfil path, data encoded into DNS
labels, cloud/database destruction (Replit, PocketOS), MCP tool-definition
labels, cloud/database destruction (Replit, PocketOS), cloud resource deletion and
removal of resource locks, backups and deletion protection (Storm-3168), MCP tool-definition
rug-pulls and typosquatted MCP packages.

## 🛡️ Stop it happening again — `agentdfir mitigate` (v2.7)
Expand All @@ -170,7 +172,8 @@ for Claude Code, a rules file for Codex, `permissions.deny` for Cursor, pinned
MCP packages and cleared auto-approve lists. Two packs are on by default and
never get in the way of legitimate work — **keep the agents' own logs** (a
`PreToolUse` guard that refuses transcript deletion) and **keep credential files
away from the agent**. Six more are opt-in, each with its friction stated.
away from the agent**. Seven more are opt-in, each with its friction stated,
including **ask before deleting cloud resources or their backups**.

```sh
agentdfir mitigate # the plan — nothing is written
Expand Down Expand Up @@ -293,7 +296,7 @@ Ships with wrappers for tools IR teams already run:
| ✅ | `simulate` — synthetic incident generation (adversary emulation for AI agents): `orphan-agent`, `toxic-chain`, and reproductions of real incidents — `keyv-hook`, `sandworm-mcp`, `s1ngularity`, `mcpoison-rugpull`, `pocketos-wipe`, `swarm-antiforensics` (v3.0) |
| ✅ | [Attack chains](docs/attack-chains.md), session cards, investigation tree, whole-case search and the hash-chained analyst case file in the [explorer](docs/serve.md) (v1.0) |
| ✅ | Full parsers for 13 products: Claude Code, Claude Cowork (desktop-app agent mode: HMAC audit log, in-VM transcripts, shared folders and egress allowlist per session), Codex CLI + Codex desktop app (rollout JSONL and the SQLite thread store, read with a stdlib-only reader that applies the write-ahead log), Gemini CLI, Cursor, Copilot CLI, Copilot Chat (VS Code), Cline, Roo, OpenClaw, OpenCode, Aider, Warp — plus Kiro (steering, specs, MCP, powers, skills and extension state; no transcript store to parse) |
| ✅ | [Enrich with a second witness](docs/endpoint-corroboration.md) — auditd, Sysmon XML, Velociraptor/osquery/eslogger/EDR exports: tool calls → CONFIRMED / DISPROVED, unlogged agent processes and connections surfaced |
| ✅ | [Enrich with a second witness](docs/endpoint-corroboration.md) — auditd, Sysmon XML, Velociraptor/osquery/eslogger/EDR exports, and AWS CloudTrail / Azure Activity Log / GCP Cloud Audit Log exports for the agent's `az` / `aws` / `gcloud` commands: tool calls → CONFIRMED / DISPROVED, unlogged agent processes and connections surfaced |
| ✅ | Reports: network-silent HTML, self-contained PDF (stdlib writer, no renderer deps), JSON, CSV, STIX 2.1, OTel · [OCSF 1.3, SARIF 2.1, Sigma export](docs/siem-interop.md) for SIEM/SOC pipelines |
| ✅ | [`serve`](docs/serve.md) — local browser case explorer: agent tree, density-scrubber timeline, raw evidence pane, findings, topology; loopback-only, zero external resources |
| ✅ | `monitor` live watch · [`--detect --alert`](docs/realtime-detection.md) real-time sensor (webhook / syslog / file) · `replay` session step-through · `investigate` explorer |
Expand Down
14 changes: 9 additions & 5 deletions docs/detection-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

| | |
|---|---|
| Rules (built-in + shipped packs) | **172** (91 built-in, 81 in `rules/`) |
| HIGH / CRITICAL rules | 117, of which **115** carry a MITRE mapping |
| Rules (built-in + shipped packs) | **175** (92 built-in, 83 in `rules/`) |
| HIGH / CRITICAL rules | 120, of which **118** carry a MITRE mapping |
| Distinct MITRE ATLAS techniques covered | **28** (ATLAS 5.6.0) |
| Distinct MITRE ATT&CK techniques covered | **69** |
| Distinct MITRE ATT&CK techniques covered | **70** |

Every HIGH/CRITICAL rule must map to at least one MITRE technique; every
`mitre_atlas` value must exist in the embedded ATLAS release. Both are
Expand Down Expand Up @@ -52,7 +52,7 @@ agentdfir rules list --packs rules --json # machine-readable
| `AML.T0086` | Exfiltration via AI Agent Tool Invocation | `CHAIN_SECRET_TO_EXFIL`, `CHAIN_SUBAGENT_CROSS_TALK_EXFIL`, `EGRESS_VIA_TRUSTED_SERVICE`, `GITHUB_EXFIL_REPO_CREATE`, `POTENTIAL_DATA_EXFILTRATION`, `CLOUD_STORAGE_UPLOAD` (agentdfir-community), `CURL_FILE_UPLOAD` (agentdfir-community), `DNS_EXFIL_LABELS` (agentdfir-community), `DNS_TUNNEL_TOOL` (agentdfir-community), `ENV_DUMP_TO_NETWORK` (agentdfir-community), `GIT_PUSH_TO_URL` (agentdfir-community), `REMOTE_COPY_TO_HOST` (agentdfir-community), `WEBHOOK_C2_EXFIL` (agentdfir-community), `PASTE_SITE_DESTINATION` (agentdfir-starter) |
| `AML.T0090` | OS Credential Dumping | `LSASS_CREDENTIAL_DUMP` (agentdfir-community), `MEMORY_CREDENTIAL_DUMP` (agentdfir-community), `SHADOW_FILE_ACCESS` (agentdfir-community) |
| `AML.T0099` | AI Agent Tool Data Poisoning | `CHAIN_MCP_RESULT_TO_DESTRUCTIVE`, `MCP_TOOL_POISONING` |
| `AML.T0101` | Data Destruction via AI Agent Tool Invocation | `CHAIN_ACTION_THEN_LOG_TAMPER`, `DESTRUCTIVE_COMMAND`, `TRANSCRIPT_REWRITTEN`, `CLOUD_DATA_DESTRUCTION` (agentdfir-community), `DISK_WIPE` (agentdfir-community) |
| `AML.T0101` | Data Destruction via AI Agent Tool Invocation | `CHAIN_ACTION_THEN_LOG_TAMPER`, `CLOUD_DESTRUCTIVE_BURST`, `DESTRUCTIVE_COMMAND`, `TRANSCRIPT_REWRITTEN`, `CLOUD_DATA_DESTRUCTION` (agentdfir-community), `CLOUD_RECOVERY_PROTECTION_REMOVED` (agentdfir-community), `CLOUD_RESOURCE_DELETION` (agentdfir-community), `DISK_WIPE` (agentdfir-community) |
| `AML.T0103` | Deploy AI Agent | `AI_CLI_HEADLESS_BYPASS`, `NESTED_AGENT_PERMISSION_BYPASS` (agentdfir-community) |
| `AML.T0110` | AI Agent Tool Poisoning | `MCP_TOOL_DEFINITION_CHANGED`, `MCP_TOOL_DESCRIPTION_POISONING`, `TOOL_POISONING_INDICATOR` |

Expand Down Expand Up @@ -96,8 +96,9 @@ agentdfir rules list --packs rules --json # machine-readable
| [`T1204`](https://attack.mitre.org/techniques/T1204/) | `REPO_INSTRUCTION_INJECTION` |
| [`T1204.002`](https://attack.mitre.org/techniques/T1204/002/) | `UNSAFE_MODEL_ARTIFACT_LOAD` (agentdfir-community) |
| [`T1222`](https://attack.mitre.org/techniques/T1222/) | `CHMOD_WORLD_WRITABLE` (agentdfir-community) |
| [`T1485`](https://attack.mitre.org/techniques/T1485/) | `CHAIN_MCP_RESULT_TO_DESTRUCTIVE`, `DESTRUCTIVE_COMMAND`, `CLOUD_DATA_DESTRUCTION` (agentdfir-community) |
| [`T1485`](https://attack.mitre.org/techniques/T1485/) | `CHAIN_MCP_RESULT_TO_DESTRUCTIVE`, `CLOUD_DESTRUCTIVE_BURST`, `DESTRUCTIVE_COMMAND`, `CLOUD_DATA_DESTRUCTION` (agentdfir-community), `CLOUD_RESOURCE_DELETION` (agentdfir-community) |
| [`T1486`](https://attack.mitre.org/techniques/T1486/) | `BULK_FILE_ENCRYPTION` (agentdfir-community) |
| [`T1490`](https://attack.mitre.org/techniques/T1490/) | `CLOUD_RECOVERY_PROTECTION_REMOVED` (agentdfir-community) |
| [`T1496`](https://attack.mitre.org/techniques/T1496/) | `CRYPTOMINER_EXECUTION` (agentdfir-community) |
| [`T1543`](https://attack.mitre.org/techniques/T1543/) | `SERVICE_PERSISTENCE` (agentdfir-community) |
| [`T1546`](https://attack.mitre.org/techniques/T1546/) | `REPO_AGENT_HOOK_AUTORUN`, `REPO_CODEX_PROJECT_CONFIG`, `REPO_DEVCONTAINER_HOST_COMMAND`, `REPO_GIT_EXEC_CONFIG`, `REPO_VSCODE_AUTORUN_TASK`, `AGENT_CONFIG_SHELL_WRITE` (agentdfir-community), `GIT_HOOK_INSTALL` (agentdfir-community), `MEMORY_INSTRUCTION_CALLOUT` (agentdfir-community) |
Expand Down Expand Up @@ -140,6 +141,7 @@ agentdfir rules list --packs rules --json # machine-readable
| CRITICAL | `CHAIN_MCP_RESULT_TO_DESTRUCTIVE` | transcript | T1485 | AML.T0099 | builtin |
| CRITICAL | `CHAIN_ORPHAN_PERSISTENCE` | transcript | T1562.001 | AML.T0081 | builtin |
| CRITICAL | `CHAIN_SECRET_TO_EXFIL` | transcript | T1048 | AML.T0086 | builtin |
| CRITICAL | `CLOUD_RECOVERY_PROTECTION_REMOVED` | command | T1490 | AML.T0101 | agentdfir-community |
| CRITICAL | `DISK_WIPE` | command | T1561 | AML.T0101 | agentdfir-community |
| CRITICAL | `JOURNAL_TAMPERED` | transcript | T1070 | - | builtin |
| CRITICAL | `KNOWN_INCIDENT_IOC` | transcript | T1195.002 | AML.T0010 | builtin |
Expand All @@ -165,9 +167,11 @@ agentdfir rules list --packs rules --json # machine-readable
| HIGH | `CHAIN_SUBAGENT_CROSS_TALK_EXFIL` | transcript | T1048 | AML.T0086 | builtin |
| HIGH | `CLOUD_CREDENTIAL_EXPORT` | command | T1552.005 | AML.T0055 | agentdfir-community |
| HIGH | `CLOUD_DATA_DESTRUCTION` | command | T1485 | AML.T0101 | agentdfir-community |
| HIGH | `CLOUD_DESTRUCTIVE_BURST` | endpoint | T1485 | AML.T0101 | builtin |
| HIGH | `CLOUD_IAM_PERSISTENCE` | command | T1098 | - | agentdfir-community |
| HIGH | `CLOUD_LOGGING_DISABLE` | command | T1562.008 | - | agentdfir-community |
| HIGH | `CLOUD_METADATA_ACCESS` | command | T1552.005 | AML.T0075 | agentdfir-community |
| HIGH | `CLOUD_RESOURCE_DELETION` | command | T1485 | AML.T0101 | agentdfir-community |
| HIGH | `CLOUD_STORAGE_UPLOAD` | command | T1567.002 | AML.T0086 | agentdfir-community |
| HIGH | `CONFIG_HOOK_REMOTE_FETCH` | config | T1059.004 | AML.T0081 | agentdfir-community |
| HIGH | `CONTAINER_ESCAPE_MOUNT` | command | T1611 | - | agentdfir-community |
Expand Down
17 changes: 16 additions & 1 deletion docs/endpoint-corroboration.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ agentdfir correlate CASE-42.adfir /var/log/audit/audit.log # Linux au
agentdfir correlate CASE-42.adfir sysmon.xml # Windows Sysmon (XML export)
agentdfir correlate CASE-42.adfir procs.jsonl netconns.csv # Velociraptor / osquery / eslogger / EDR exports
agentdfir analyze CASE-42.adfir --endpoint audit.log # same, inside the one-shot analysis
agentdfir analyze CASE-42.adfir --endpoint cloudtrail.json # cloud audit export: the agent's az / aws / gcloud commands
```

Format is sniffed per file (`--format auditd|sysmon-xml|jsonl|csv` to override). `--window 3s` sets the match window. Results are written back to `normalized/events.jsonl` (states + an evidence note naming the confirming record) and to `detections/corroboration.json`; `triage` merges the findings so every downstream report, OCSF/SARIF export and PDF carries the upgraded states.
Format is sniffed per file (`--format auditd|sysmon-xml|jsonl|csv|cloud-audit` to override). `--window 3s` sets the match window. Results are written back to `normalized/events.jsonl` (states + an evidence note naming the confirming record) and to `detections/corroboration.json`; `triage` merges the findings so every downstream report, OCSF/SARIF export and PDF carries the upgraded states.

## Supported telemetry

Expand All @@ -29,6 +30,12 @@ Format is sniffed per file (`--format auditd|sysmon-xml|jsonl|csv` to override).
| **Sysmon** | `wevtutil qe Microsoft-Windows-Sysmon/Operational /f:xml > sysmon.xml` | EventID 1 process, 3 network, 11/23/2 file |
| **Generic JSONL / CSV** | Velociraptor (`Linux.Events.ProcessExecutions`, `Windows.System.Pslist`…), osquery `process_events`, `evtx_dump -o jsonl`, macOS `eslogger exec open create unlink` | nested JSON flattened; ~90 field aliases cover pid/ppid/exe/cmdline/parent/user/dest ip+port/file path |

| **AWS CloudTrail** | the trail's S3 objects (`{"Records":[…]}`), `aws cloudtrail lookup-events` output, or events one per line | cloud: service and API call, principal ARN, source IP, request resource names, error code |
| **Azure Activity Log** | `az monitor activity-log list -o json`, the REST `{"value":[…]}` shape, or diagnostic-settings `{"records":[…]}` blobs | cloud: Resource Manager operation, caller, resource id, client IP, Failed status |
| **GCP Cloud Audit Logs** | `gcloud logging read 'logName:cloudaudit.googleapis.com' --format=json` | cloud: service and method, principal email, resource name, caller IP, status code |

Cloud exports are read from files only: nothing calls a cloud API.

Raw `.evtx` is not parsed — export first (documented limitation). macOS unified log lacks exec argv; use `eslogger` (Endpoint Security) output.

## What the engine does
Expand All @@ -43,8 +50,16 @@ Raw `.evtx` is not parsed — export first (documented limitation). macOS unifie
| `UNLOGGED_AGENT_ACTIVITY` | MEDIUM | agent-lineage process exec with no transcript tool call (grouped per program, runtime helpers filtered) | `nc 185.10.10.10 4444` spawned under the agent, not in any transcript |
| `UNLOGGED_AGENT_NETWORK` | HIGH | agent-lineage connection to a non-allowlisted destination with no transcript reference | Cursor's `node` child connects to `185.x.x.x:4444` |

| `CLOUD_DESTRUCTIVE_BURST` | HIGH | a cloud audit log shows one identity deleting 10+ distinct resources within 10 minutes (refused calls do not count) | a leaked service principal deletes a dozen storage accounts in six minutes |

Contradiction requires **process** telemetry covering that moment; with only network or file records, unmatched commands stay OBSERVED.

### Cloud audit logs

An agent's `az`, `aws` or `gcloud` command is **CORROBORATED** when the control plane recorded the same operation within ±2 minutes, on the same resource when the command names one: `az storage account delete -n acct1` matches `Microsoft.Storage/storageAccounts/delete` on `…/storageAccounts/acct1`, `aws s3 rb s3://b` matches `s3:DeleteBucket` for `b`, `gcloud sql instances delete db1` matches `cloudsql.instances.delete` on `…/instances/db1`. When the cloud refused the call, the note says so and names the error.

A cloud log never **contradicts** a command. The export may be for a different account, subscription or project, so a missing record means nothing. Cloud records also do not count as host telemetry: a cloud-only export gives no process coverage.

## Example

```
Expand Down
3 changes: 2 additions & 1 deletion docs/hunt.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ agentdfir hunt --list # incidents, indicator counts, s
Exit status is `1` when an incident's indicators are present, `0`
otherwise, so it drops into scripts and CI.

## Incidents shipped (pack `agentdfir-incidents` v1)
## Incidents shipped (pack `agentdfir-incidents` v2)

Every indicator is copied from the cited write-up; nothing is inferred.
`--list` prints the sources.
Expand All @@ -31,6 +31,7 @@ Every indicator is copied from the cited write-up; nothing is inferred.
| `codexui-android` | Codex token theft, Apr–May 2026 | `codexui-android`, `@friuns/codexui`, `sentry.anyclaw.store`, XOR key |
| `keyv-wave` | Shai-Hulud keyv / cacheable wave, Aug 2026 — committed SessionStart hook + folderOpen task | `keyv@6.0.0` and siblings, `npm-cache.com`, payload file names, repo description |
| `amazon-q-wiper` | Amazon Q VS Code 1.84.0 wiper prompt, Jul 2025 | the extension install directory |
| `storm-3168-jadepuffer` | LLM-driven cloud and database destruction, Jun–Sep 2026 (Microsoft Storm-3168, Sysdig JADEPUFFER) | the three published attacker addresses; Langflow below 1.3.0 (CVE-2025-3248, the entry point) at low confidence, because a vulnerable version is exposure, not compromise |

Incidents without host indicators (Anthropic's GTG-1002 / GTG-2002 reports,
the OpenAI–Hugging Face agent intrusion, Replit, PocketOS) are covered by
Expand Down
Loading
Loading