An autonomous DFIR agent that finds evil in the contradictions an attacker leaves behind.
SANS Find Evil! · Architecture pattern #2 (Custom MCP Server) · precision 1.00 · recall 1.00 · 0 false positives
Live Console · Try it · How it works · Architecture · Accuracy
An attacker can rewrite a timestamp in seconds. They cannot rewrite live memory.
Every other defender's agent runs a forensic tool and believes the output. But the attacker's last act on a host is lying to 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.
CONTRA encodes that instinct. It assumes the evidence is lying, weights every artifact by forge cost, and finds evil in the contradictions. Self-correction isn't "I made a mistake" — it's "the disk is gaslighting me."
CONTRA ships as a real read-only MCP server. No disk image, no VPS, no config — three forensic sample cases are bundled. Pick a path:
Open this repo in Claude Code (or paste it to any Claude with tools) and say:
"Set up CONTRA and triage the sample case."
It reads CLAUDE.md and installs + registers + runs itself.
pip install "git+https://github.com/Venkat5599/CONTRA.git"
contra-setup # auto-registers in Claude Desktop — no JSON editingFully quit & reopen Claude Desktop, then ask:
"List the contra cases, then triage case_blackcat and explain the evil."
Expect:
MALICIOUS ACTIVITY CONFIRMED
R1 T1070.006 Timestomp believe $FILE_NAME > $STANDARD_INFORMATION (forged)
R2 T1055 fileless believe volatility3.pslist > filesystem
R3 T1070.001 cleared logs believe SrumECmd > eventlog
Then triage case_clean → NO EVIL FOUND (proves zero false positives).
pip install -e . && python -m contra.demo_offlineFull client setup (Cursor / Cline / manual config):
docs/submission/MCP_INSTALL.md
CONTRA decouples judgment (an LLM) from truth (a deterministic engine):
LLM planner ─ reasons about evidence reliability, picks the next forensic tool
│
Read-only MCP surface ─ typed forensic tools only; no shell, no write, no delete
│
Contradiction engine ─ DETERMINISTIC: diffs sources by trust, names the technique
│
Self-correction loop ─ contradiction → re-weight belief → pivot to confirm
│
Provenance ─ every finding → exact command + SHA-256 of the evidence
The LLM only decides sequencing. The findings — the integrity-critical part — are deterministic and reproducible. That's the split judges can stand behind in court.
| Artifact | Forge cost | Trust |
|---|---|---|
| Memory (process, netconn, injection) | very high | 0.95 |
$FILE_NAME timestamps (NTFS) |
high | 0.90 |
$UsnJrnl / $LogFile journal |
high | 0.85 |
| Prefetch / Amcache / SRUM | medium-high | 0.80 |
| Windows Event Logs | clearable | 0.40 |
$STANDARD_INFORMATION timestamps |
trivial | 0.30 |
| Rule | Contradiction | Technique |
|---|---|---|
| R1 | $SI predates / contradicts $FN |
T1070.006 Timestomp |
| R2 | process in memory, no file on disk | T1055 Process Injection / fileless |
| R3 | SRUM shows activity, event log empty | T1070.001 Clear Windows Event Logs |
| R4 | $UsnJrnl create+delete, file gone |
T1485 Data Destruction |
| R5 | Amcache proves exec, no prefetch | T1070.004 File Deletion |
Pattern #2 — Custom MCP Server. The guardrail is architectural, not a prompt.
SIFT tools (volatility3 · MFTECmd · PECmd · AmcacheParser) ← invoked read-only
│
══════╪══════════════ ARCHITECTURAL BOUNDARY ══════════════
│ destructive functions DO NOT EXIST here
READ-ONLY MCP SURFACE
get_mft_record · list_memory_procs · get_amcache · triage_case · …
│ every return → { value, trust, raw_cmd, evidence_sha256 }
CONTRADICTION ENGINE (deterministic) → AUTONOMOUS LOOP → PROVENANCE
There is no execute_shell, no write_file, no dd/rm on the surface. A prompt
injection inside the case data cannot construct a destructive call — the function isn't
there. Verified by a live bypass test: dd, rm, --write, and a shell escape are
all refused at the architecture, while read-only calls succeed.
📄 Full diagram + trust boundaries: docs/submission/ARCHITECTURE_DIAGRAM.md
Reproducible — python -m contra.eval.run_evals --pass-k 3:
| Case | Type | Findings | FP | FN | Precision | Recall |
|---|---|---|---|---|---|---|
case_blackcat |
attack | 3 / 3 | 0 | 0 | 1.00 | 1.00 |
case_silentexfil |
attack | 2 / 2 | 0 | 0 | 1.00 | 1.00 |
case_clean |
benign | 0 / 0 | 0 | 0 | 1.00 | 1.00 |
| Aggregate | 5 / 5 | 0 | 0 | 1.00 | 1.00 |
Stable over pass^3. Validated on real tool output — R1 fires on a genuine timestomp
parsed from real MFTECmd 2026.5 over a real NTFS $MFT extracted with Sleuthkit on a
SIFT workstation. Real data even hardened the rule (the impossible-ordering signal was
forced by genuine output — documented, not hidden).
📄 Full accuracy report + spoliation test: docs/submission/ACCURACY_REPORT.md
contra-dfir.vercel.app — watch the agent reason, self-correct, and catch the lie in a live investigation replay: plan → observe → CORRECT (contradiction caught, in red) → pivot. Every finding traces to its command and evidence hash. Switch cases to see attacks light up and the benign host stay quiet.
contra/
trust.py Evidence Trust Hierarchy + trust-tagged envelope
mcp_server.py the installable read-only MCP surface (11 tools)
contradiction.py deterministic R1–R5 anti-forensic engine
agent.py autonomous loop · max-iter cap · JSONL traces
planner_llm.py LLM planner (genuine autonomous tool sequencing)
provider_real.py runs LIVE SIFT tools on a host over the read-only boundary
parsers.py real MFTECmd / volatility3 / amcache parsers
install_desktop.py one-command Claude Desktop installer (contra-setup)
eval/ accuracy harness (precision/recall vs ground truth)
fixtures/ 3 sample cases + real captured MFTECmd output
web/ the evidence console (React + Vite)
tools/vps_scripts/ provision real SIFT toolchain on a Linux host
docs/submission/ all SANS deliverables (accuracy, dataset, story, …)
tests/ 21 tests — guardrail, accuracy, MCP surface, real parsers
pip install -e ".[dev]" && pytest -q # 21 passingNot a bigger model. A better way for the agent to doubt.
Deterministic trust math under an LLM's judgment — autonomy you can stand behind.
MIT · contra-dfir.vercel.app · #findevil