CONTRA

The forensic agent that assumes the evidence is lying.

An autonomous DFIR agent that finds evil in the contradictions an attacker leaves behind. Ships as a real read-only MCP server. Precision 1.00 · recall 1.00 · zero false positives.


Inspiration

We kept noticing the same blind spot in every "AI for security" demo: the agent runs a forensic tool and believes the output. But the attacker's final act on a host is lying to exactly those tools — timestomping the binary, clearing the event log, wiping the dropper. An agent that trusts artifacts at face value walks straight into the deception.

A senior analyst never does this. They rank evidence by how expensive it is to forge. $STANDARD_INFORMATION is trivial to fake; $FILE_NAME needs kernel access; live memory cannot be retroactively forged at all. When two sources disagree, the analyst believes the expensive one and treats the cheap, contradicting one as the crime scene. We wanted to encode that instinct — not a bigger model, a better way for the agent to doubt.

What it does

CONTRA is an autonomous DFIR agent that assumes the evidence is lying. It weights every artifact by forge cost, diffs the sources, and finds evil in the contradictions.

  • Triages forensic cases end to end: it plans, runs read-only forensic tools, catches contradictions, self-corrects, and pivots to confirm.
  • Names the technique. Five anti-forensic contradictions map straight to MITRE ATT&CK: timestomp (T1070.006), fileless process injection (T1055), cleared event logs (T1070.001), data destruction (T1485), file deletion (T1070.004).
  • Proves every finding. Each result traces to the exact command that produced it and a SHA-256 of the evidence — provenance you can stand behind in court.
  • Stays quiet on benign hosts. A clean case returns NO EVIL FOUND — zero false positives.

How we built it

CONTRA decouples judgment (an LLM) from truth (a deterministic engine):

  • Evidence Trust Hierarchy (trust.py) — every artifact is wrapped in a trust-tagged envelope scored by forge cost: live memory 0.95, $FILE_NAME 0.90, journals 0.85, Prefetch/Amcache/SRUM 0.80, event logs 0.40, $STANDARD_INFORMATION 0.30.
  • Read-only MCP server (mcp_server.py) — 11 typed forensic tools and two analytical tools. There is no execute_shell, no write_file, no dd/rm. The guardrail is architectural, not a prompt.
  • Deterministic contradiction engine (contradiction.py) — the R1–R5 rules diff sources by trust and name the technique. Reproducible and court-defensible.
  • Autonomous loop (agent.py + planner_llm.py) — the LLM only decides tool sequencing; the findings are deterministic. Max-iteration cap, JSONL traces.
  • Real provider (provider_real.py + parsers.py) — runs live SIFT tools (volatility3, MFTECmd, PECmd, AmcacheParser) over the read-only boundary, with real parsers.
  • Evidence console (web/, React + Vite) — replays the investigation: plan → observe → CORRECT (contradiction caught, in red) → pivot.
  • Eval harness (eval/) — precision/recall vs ground truth, stable over pass^3.

Challenges we ran into

  • Trusting an LLM with integrity-critical output. We solved it by refusing to. The LLM never produces a finding — it only picks the next tool. Truth stays deterministic.
  • Making the guardrail real, not a promise. Prompts can be jailbroken. So we removed destructive functions from the MCP surface entirely and proved it with a live bypass test: dd, rm, --write, and a shell escape are all refused at the architecture while read-only calls succeed.
  • Real tool output is messy. Validating R1 on genuine MFTECmd 2026.5 output over a real NTFS $MFT (extracted with Sleuthkit on a SIFT workstation) forced us to harden the rule — the impossible-ordering signal came from real data, documented, not hidden.
  • Zero false positives. Tuning the contradiction rules so a benign host stays completely silent was harder than catching the attacks.

Accomplishments that we're proud of

  • Precision 1.00, recall 1.00, zero false positives across all cases — stable over three passes.
  • Validated on real tool output, not just synthetic fixtures.
  • An architectural guardrail that survives prompt injection by design — confirmed by a live bypass test.
  • Full provenance — every finding ties to its command and an evidence hash.
  • Ships installable — a real read-only MCP server with one-command setup, plus a live console anyone can try.

What we learned

  • The path to trustworthy autonomy isn't a smarter model — it's a smaller surface and deterministic truth under the model's judgment.
  • The most useful security primitive is forge cost: ranking evidence by how hard it is to fake changes what the agent believes.
  • Self-correction lands hardest when it's framed as "the disk is gaslighting me," not "I made a mistake."
  • Architectural guardrails beat prompt guardrails every time — you can't jailbreak a function that doesn't exist.

What's next for CONTRA

  • More contradiction rules beyond R1–R5 — registry vs Amcache, ShimCache vs Prefetch, memory vs network.
  • Live host triage at scale — point CONTRA at a fleet over the read-only boundary, not just sample cases.
  • More platforms — extend the trust hierarchy to Linux (auditd, ext4 journals) and cloud (CloudTrail vs runtime).
  • Analyst-in-the-loop console — let a human accept, reject, or escalate findings with the provenance attached.
  • Ecosystem integrations — push findings to SIEM/SOAR with the MITRE mapping and evidence hash intact.

Not a bigger model. A better way for the agent to doubt. · contra-dfir.vercel.app · #findevil

Built With

  • amcacheparser
  • anthropic-claude
  • claude-code
  • mftecmd
  • mitre-attack
  • model-context-protocol
  • ntfs
  • pecmd
  • pytest
  • python
  • react
  • sift-workstation
  • sleuthkit
  • typescript
  • vite
  • volatility3
Share this project:

Updates