DFIR Autonomous Investigation Agent
What it does
This is an autonomous memory forensics agent that investigates Windows memory images end to end — collecting evidence, reasoning over it, validating its own conclusions, and generating a traceable incident report — without any human in the loop.
The agent takes a raw memory dump, runs a structured set of Volatility 3 plugins, and produces a JSON evidence store where every tool execution has a unique evidence ID. An investigator agent then reasons over that evidence: it requests specific views, filters by PID, runs additional plugins when needed, and produces findings where every claim cites at least one evidence ID. A separate verifier agent independently reviews each finding against its cited evidence and rejects anything it cannot support. The final HTML report shows accepted findings with full evidence citations alongside a "Rejected Findings" section that documents what the verifier caught.
The problem it solves
DFIR analysts spend hours on memory triage. Running Volatility plugins is the easy part. The hard part is the reasoning layer: correlating a suspicious process in pslist with an injected region in malfind and an outbound connection in netscan, then writing a finding that would hold up in a legal context. That requires evidence citations, not just conclusions.
The standard LLM-over-tools approach fails here because LLMs hallucinate. An AI report that says "PID 1640 is malicious" without citing the specific tool output that proves it is useless in real incident response. I built the verifier specifically to address this: every claim has to survive independent scrutiny before it goes in the report.
How I built it
Evidence store: every Volatility execution produces a structured artifact with a unique evidence ID, the exact command run, the timestamp, raw output, and parsed JSON rows. This is the chain of custody layer. Nothing downstream can reference evidence that was not actually collected.
Investigator agent: an LLM that receives an evidence overview and the process list upfront, then operates on a 10-action budget. Each turn it chooses one action: inspect an evidence item, filter by PID, run an additional plugin, or finalize. Every finding it produces must include evidence IDs that exist in the store.
Verifier agent: a completely separate LLM pass. It receives each finding alongside the raw evidence it cited and issues an independent verdict: accept or reject with a reason. It has no access to the investigator's reasoning — only the claim and the cited evidence. This is what produces genuine self-correction rather than scripted retries.
Report generator: produces an HTML report with a PDF export button. Accepted findings show the claim, confidence level, category, cited evidence IDs, and verifier rationale. Rejected findings appear in a separate section with the verifier's rejection reason. The methodology section explains the pipeline so another analyst can understand and trust the output.
Caching: Volatility results are cached to disk by a hash of the image path and plugin name. LLM responses are cached by a hash of the message contents. This means iterating on prompts does not re-run expensive tool calls or burn API tokens on unchanged inputs.
Challenges
The biggest challenge was token budget management. Volatility plugins like dlllist and netscan produce hundreds of rows. Feeding full output into an LLM context across 10 turns hits free-tier rate limits fast. I solved this with aggressive row capping in the summarizer and a sliding window over conversation history that keeps only the system prompt, the initial evidence, and the last few turns.
The second challenge was agent looping. Without tracking, the agent re-ran plugins and re-inspected evidence it had already seen. I blocked repeat plugin calls at the code level, which works reliably. On the lightweight 8B model the agent still occasionally repeats filter actions within a run — a known limitation I'd address with a stronger investigator model or stricter action deduplication.
The third challenge was genuine self-correction versus scripted correction. Most approaches inject a fake error and show a clean recovery. My verifier catches real problems: hallucinated evidence IDs that do not exist in the store, evidence that does not support the specific claim made, and overclaiming from weak single-source signals. These rejections happen naturally on every run and are logged in verified.json.
What I learned
Memory forensics reasoning is more structured than I expected. The heuristics analysts use — wrong parent PIDs, executables outside System32, PAGE_EXECUTE_READWRITE in malfind, PID overlap between malfind and netscan — are encodable as prompt heuristics that make the agent's reasoning predictable and auditable. The agent works best when it is given a forensic playbook rather than generic instructions.
The verifier architecture is the part I would carry into production. Separating the investigator from the verifier means the validation layer has no incentive to confirm the investigator's conclusions. It is the same principle as peer review: the reviewer does not know what answer the author wanted, only whether the evidence supports the claim.
Accuracy report
Documented failure modes observed during development and testing:
- Hallucinated evidence IDs (e.g. EV-948 instead of a real 8-character ID): caught by verifier on every occurrence, finding rejected
- Early finalization before full inspection: the system prompt instructs the agent to inspect key plugins before finalizing; on the 8B model this is followed inconsistently.
- Redundant plugin calls: fixed architecturally by blocking repeat runs at the executor level
- Overclaiming from single-source signals: verifier rejects high-confidence claims that cite only one weak evidence item
All rejected findings are preserved in evidence/verified.json and shown in the report. The pipeline is designed so that a failed verification is visible output, not a hidden error.
Log in or sign up for Devpost to join the conversation.