Skip to content

Offline gpt-oss:20b DFIR test + automated scorecard grader - #36

Merged
TimothyVang merged 1 commit into
mainfrom
agent/offline-dfir-llm-scorecard
Jul 12, 2026
Merged

Offline gpt-oss:20b DFIR test + automated scorecard grader#36
TimothyVang merged 1 commit into
mainfrom
agent/offline-dfir-llm-scorecard

Conversation

@TimothyVang

Copy link
Copy Markdown
Owner

What

Adds the automated grader the offline DFIR battery was missing, plus real captured evidence from running the investigate pipeline fully offline on the DGX Spark GB10 with gpt-oss:20b forced as the agent (CASEFORGE_FORCE_AGENT=1).

Honest headline

Offline detection works; the LLM did not author it. Across all three battery cases the deterministic find_evil_auto engine elevated 13/13 expected MITRE techniques + CVEs and produced custody-sealed, manifest_verify-PASS cases — but in all three runs gpt-oss:20b failed to seal (repeated invalid tool calls) and caseforge fell back to the deterministic engine. Every sealed verdict.json carries agent: "find-evil-auto MVP". This proves offline forensic detection, not that the LLM can drive a sealed offline investigation (it currently cannot on 20b).

case score verdict seal provenance
win-lateral-movement 3/3 HIT INDETERMINATE deterministic-fallback
attack-samples 5/5 HIT SUSPICIOUS deterministic-fallback
bench-evtx-2026-07-03 5/5 HIT INDETERMINATE deterministic-fallback

Changes

  • scripts/score-offline-run.mjs — parse a sealed verdict.json, diff elevated MITRE techniques/CVEs vs the oracle to HIT/PARTIAL/MISS + score, and report llm_provenance (llm-agent vs deterministic-fallback). --require-llm exits non-zero when the seal came from the fallback — the gate to flip on once the agent can seal.
  • fixtures/dfir-scorecard/ground-truth.json — machine-readable oracle (vendored from the lab scorecard).
  • fixtures/dfir-scorecard/runs/*.verdict.json — the three real sealed offline runs (evidence + CI fixtures).
  • scripts/selftest.mjs — scorecard assertions wired into CI; encodes the "all fell back" finding as tests.
  • docs/offline-llm-test.md — full honest write-up + reproduction.

Test plan

  • node scripts/selftest.mjs (CI step) covers the grader: 11 scorecard assertions — full technique elevation per case, deterministic-fallback provenance flagged on all three, LLM-authored recognition, and a regression guard.
  • Reproduce a live offline run: CASEFORGE_FORCE_AGENT=1 VERDICT_LLM_MODEL=gpt-oss:20b bash evidence/run-investigate-local.sh evidence/real-evtx-20260708/win-lateral-movement

"Offline" = local-only inference (localhost Ollama, --privacy local-only, no cloud/Claude creds); local-only, not air-gapped.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b09ed6c358

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +171 to +172
const verdict = JSON.parse(readFileSync(verdictPath, "utf8"))
const r = scoreRun(verdict, caseGt)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require custody verification before scoring

The grader's CLI reads a standalone verdict.json and immediately scores it, so neither run.manifest.json nor manifest_verify.json/audit-chain custody is checked before returning success. In the documented offline scorecard gate, a stale or fabricated verdict containing the expected techniques plus agent: "verdict (gpt-oss:20b)" can pass --min-score and --require-llm even with no verified manifest, undermining the repository's custody-first guarantee; require a run directory and validate custody before success.

Useful? React with 👍 / 👎.

Comment thread scripts/selftest.mjs
Comment on lines +608 to +609
const runFixture = (name) =>
JSON.parse(readFileSync(fileURLToPath(new URL(`../fixtures/dfir-scorecard/runs/${name}.verdict.json`, import.meta.url)), "utf8"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep real EVTX outputs out of CI selftest

The workflow runs node scripts/selftest.mjs under a documented synthetic-only CI policy, but this loader pulls the new scorecard fixtures whose docs/contents identify them as captured real EVTX outputs, including evidence_path values under evidence/real-evtx-20260708 with hosts/accounts/IPs. That makes every CI run depend on non-synthetic evidence and publishes local case data; replace these with synthetic/minimized redacted fixtures or keep the real runs outside the repo/CI.

Useful? React with 👍 / 👎.

@TimothyVang

Copy link
Copy Markdown
Owner Author

Status: shipped + CI green ✅

The offline EVTX test is landed and verified:

  • build-and-verify CI passing, branch MERGEABLE.
  • 3 real offline runs on the DGX Spark GB10 (gpt-oss:20b, CASEFORGE_FORCE_AGENT=1), all custody-sealed with manifest_verify PASS.
  • 13/13 detection targets HIT across win-lateral-movement (3/3), attack-samples (5/5), bench (5/5).
  • The grader's 11 scorecard assertions pass in CI — including the ones that assert every seal is a deterministic-fallback.

Honest scope (unchanged): this proves the offline detection floor (the deterministic find_evil_auto engine). It does not prove the LLM can drive a sealed offline investigation — gpt-oss:20b fell back in all three runs on invalid tool calls. The --require-llm gate is built and ready to flip on the day a model seals without falling back.

Next: a real forensic-image benchmark — full disk images (E01/dd), not just EVTX — to exercise the disk_mount / disk_extract_artifacts / vol_* / mft_timeline tool surface with disk-level ground truth. Planning now; the grader here is the scoring substrate it will extend.

Add the automated grader the offline battery lacked, plus real captured
evidence from running the investigate pipeline offline on the DGX Spark with
gpt-oss:20b forced as the agent (CASEFORGE_FORCE_AGENT=1).

- scripts/score-offline-run.mjs: parse a sealed verdict.json, diff elevated
  MITRE techniques/CVEs vs fixtures/dfir-scorecard/ground-truth.json
  (HIT/PARTIAL/MISS + score), and report llm_provenance so a passing detection
  score is never mistaken for the LLM having authored the seal. --require-llm
  gates non-zero on deterministic fallback.
- fixtures/dfir-scorecard/: ground-truth oracle + three real sealed verdict.json
  runs (win-lateral-movement, attack-samples, bench).
- scripts/selftest.mjs: scorecard assertions wired into CI.
- docs/offline-llm-test.md: honest results.

Result: detection floor is complete (13/13 targets HIT, all custody-sealed),
but all three runs fell back to the deterministic find_evil_auto engine after
gpt-oss:20b failed to seal on invalid tool calls. The LLM authored none of the
seals; the grader's llm_provenance makes that explicit.
@TimothyVang
TimothyVang force-pushed the agent/offline-dfir-llm-scorecard branch from b09ed6c to 06986dc Compare July 12, 2026 00:28
@TimothyVang
TimothyVang merged commit f6a0124 into main Jul 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants