INSPIRATION
Every DFIR tool we know asks the same question: what happened?
We came from a different direction. One of us has a background in semiotics and mathematics, not computer science. The first question we ask when we see a forensic artifact is not "what is this?" but "why does this look this way?"
That reframing changed everything.
Sophisticated attackers can delete logs, forge timestamps, and suppress technical indicators. What they cannot do is maintain cross-artifact semiotic coherence across an entire investigation. Deliberate deception leaves fractures — structural inconsistencies between what the evidence claims and what the evidence implies.
VIGÍA was built to find those fractures.
WHAT IT DOES
VIGÍA analyzes digital forensic artifacts and produces Daubert-admissible verdicts on actor intentionality. It does not look for known malware signatures or IoC patterns. It looks for Indicators of Intent.
The five IoI classes VIGÍA detects:
- Performed incompetence — technical perfection combined with claimed ignorance
- Excessive digital perfection — entropy too low, timing too regular, behavior too clean for a human actor
- Significant silences — the absence of expected artifacts is itself evidence
- Impossible timing — effects that precede their causes, actions that violate causal order
- Narrative fractures — cross-artifact incoherence between what the evidence says and what it implies
Verdict scale:
| Verdict | Meaning | Daubert bar |
|---|---|---|
MALICE |
Active concealment of intent | Two independent sources + Refutation Protocol + devil_advocate populated |
INTENT |
Deliberate decisions produced this outcome | Two independent sources + Refutation Protocol |
SUSPICION |
Structural anomaly, no confirmed deliberate concealment | Single source, documented baseline deviation |
NOISE |
Fully explained by misconfiguration or normal behavior | Single source sufficient |
ABSTAIN |
Insufficient evidence — mathematically justified refusal | Document gap explicitly |
UNKNOWN |
Anomaly detected but unclassifiable | — |
BENIGN |
Activity confirmed legitimate | — |
INCONCLUSIVE |
Contradictory evidence — corroboration required | — |
The distinction between INTENT and MALICE is the concealment layer.
When the evidence is insufficient, a forensic engine that forces a verdict is dangerous. VIGÍA emits ABSTAIN rather than guess. The quadripartite state CORROBORATE_THEN_ACT tells the investigator exactly what to do next.
The sealed ForensicBundle:
Every investigation produces a cryptographically sealed bundle with four hashes:
- H1: evidence graph hash
- H2: bundle integrity hash
- H3: file SHA-256 (independently verifiable)
- H4: engine attestation hash
The same input produces the same four hashes on any machine, any run, any architecture. This is a Daubert admissibility requirement: the analysis must be reproducible by an opposing expert.
Where VIGÍA sits in the forensic stack:
Raw evidence
↓
[Other tools: "Is the agent lying about what it sees?"]
↓
VIGÍA: "Assuming the evidence is authentic — is the attacker lying?"
These are two different layers of the forensic stack. VIGÍA operates on the second.
OPERATING MODES
VIGÍA runs in five modes. The deterministic core is identical across all of them.
Mode 1 — Python fallback (0 tokens, no internet required)
The full scoring pipeline runs without any LLM. Deterministic Fraction arithmetic, CAIE cross-artifact fusion, temporal analysis, behavioral fingerprinting — all locally. Zero API cost. Zero network dependency.
In our demo, five cases resolve correctly in under 0.05 seconds each in fallback mode. This makes VIGÍA viable for air-gapped environments, resource-constrained teams, and investigations involving classified material that cannot leave the network.
Mode 2 — Ollama (local LLM, no data leaves the machine)
Semantic analysis tools activate with a local model (tested: hermes3:8b, deepseek-r1:8b, gemma3:27b). The mathematical verdict pipeline is unchanged. Ollama mode is for teams that need LLM-enhanced narrative generation without sending evidence to external APIs.
Mode 3 — Claude Code + MCP (full investigation mode)
VIGÍA exposes 21 forensic tools as MCP functions. Claude Code reads CLAUDE.md at the repository root and conducts a full Peircean investigation interactively, calling tools in sequence, applying the mandatory self-correction protocol, and generating an Amicus Curiae narrative suitable for judicial submission.
The LLM is strictly downstream of the mathematical decision: the bundle is sealed before the narrative is generated. The LLM explains. It does not decide.
Mode 4 — Autonomous agent (vigia_agent.py)
Batch processing for multiple cases. The agent runs up to 3 self-correction iterations, detects contradictions, and seals the bundle automatically.
The canonical corpus is distributed as JSON for reproducibility.
However, several VIGIA-REAL cases were originally processed from production-scale forensic images using Volatility3 and SIFT Workstation. The published JSON cases represent the extracted evidential state after acquisition and triage, allowing deterministic reproduction without requiring multi-gigabyte evidence files.
Mode 5 — OpenWebUI (experimental)
Browser-based investigation interface via MCP server. Functional; accuracy validation in progress.
THE KASSANDRA PROTOCOL
VIGÍA defends against a threat that most forensic tools ignore: adversarial evidence — artifacts crafted specifically to manipulate the analysis engine.
The Kassandra Protocol plants a cryptographic tripwire inside every evidence payload sent to the LLM. If the LLM detects an embedded prompt injection attempt, it must return MALICE with confidence=100. If it returns anything else, the response is marked INTEGRITY_UNKNOWN and blocked from influencing the bundle.
An attacker who plants manipulative content in a log file does not just fail to deceive VIGÍA. They trigger an escalation to maximum confidence MALICE and leave an immutable record in the audit chain.
HOW WE BUILT IT
Theoretical foundation: Peircean semiotics (Firstness/Secondness/Thirdness), Eco's theory of overinterpretation, Grice's cooperative principle, Carnegie persuasion taxonomy.
Mathematical core: Uses Python fractions.Fraction arithmetic with precision=28. Mathematical core: Scoring uses Python fractions.Fraction for the verdict classifier and canonical bundle output; decimal.Decimal (precision=28) for intermediate aggregations. Float intermediates exist in the scoring path and are documented in KNOWN_LIMITATIONS.md (L-021). The bundle hash is deterministic: SHA-256 over canonical JSON. The same input produces the same bundle_hash on x86 and ARM.
Acquisition assurance: SHA-256 hash chain at every layer. HMAC-verified audit trail. NIST SP 800-86 trust penalties for missing chain of custody fields. write_blocker_used, examiner_id, and acquisition_hash are required fields — their absence degrades the verdict score mathematically.
Self-correction: Before any MALICE verdict, VIGÍA applies the Mandatory Refutation Protocol (Eco's Razor): formulate the strongest innocent explanation, test it against the complete evidence set, document the result in devil_advocate. An empty devil_advocate field invalidates the verdict under Daubert.
Multi-AI audit: The system was developed and audited by a collective of AI systems — Kimi/Moonshot as primary forensic auditor, Claude as primary implementer, with red-teaming from DeepSeek, Gemini, Qwen, and ChatGPT. Audit findings are treated as binding technical directives.
SIFT integration: VIGÍA operates on artifacts already extracted by the SIFT Workstation. No workflow disruption. Output is a sealed ForensicBundle compatible with existing SIFT chain of custody.
CHALLENGES
The hardest problem was the corroboration gate. A single perfect artifact — however high its raw score — is insufficient for MALICE under Daubert. The system requires n_artifacts >= 4 OR n_unique_types >= 3 for the strongest verdict. This is epistemologically correct but forces careful case design: VIGÍA will refuse to escalate even when the evidence looks overwhelming, if the evidence is homogeneous.
The second hardest problem was keeping floats out of the scoring pipeline entirely. Several early integrations silently introduced float contamination through library interfaces. Every path was audited and replaced with Fraction or Decimal.
WHAT WE LEARNED
The most important lesson: honest documentation of limitations is a forensic asset, not a liability. A system that says "I don't know" (ABSTAIN) and documents why is more reliable than one that forces a verdict. The same principle applies to our accuracy report — we documented every known failure mode because investigators using this in production need to know the boundaries of what it detects. We learned that keeping floats out of a complex pipeline is a discipline problem, not an engineering problem. Every third-party library is a potential contamination vector. The audit had to be exhaustive: every computation path, every aggregation step. We learned that sophisticated self-correction is architectural, not narrative. VIGÍA's Mandatory Refutation Protocol runs before every MALICE verdict and is logged immutably. The correction that appears in the demo — downgrading DFIR tooling from INTENT to SUSPICION after cross-artifact recognition — is not the LLM changing its mind. It is the scoring engine refuting its own initial hypothesis against the complete evidence set. We learned that multi-AI auditing at scale (six models, iterative rounds) produces a qualitatively different result than any single model review. Each model finds different classes of vulnerabilities. The architecture that emerged from that process is more adversarially robust than any single-architect design.
ACCOMPLISHMENTS
- 163 passed, 6 xfailed (TEST)
- 16/17 real cases correct in deterministic fallback mode (REAL-007 resolves correctly via agent pipeline)
- 52/52 canonical cases passing Full Amicus Curiae with 14 timestamped MCP tool calls generated for VIGIA-REAL-VANKO (insider threat / IP exfiltration, SANS FOR500 corpus) — self-correction F-004: INTENT → SUSPICION after applying Daubert single-source standard to WiFi reconnaissance artifacts. Tool execution log embedded in sealed bundle JSON. Full Amicus Curiae for VIGIA-REAL-SRL-DMZ-FTP — self-correction F-003: INTENT → SUSPICION after recognizing legitimate DFIR tooling (F-Response/Mnemosyne.sys).
- Sub-50ms verdict on all fallback cases
- EBS v1 bundle format independently verifiable with zero dependencies (
verify_ebs_v1.py, stdlib only)
Accuracy
VIGÍA separates evaluation into three distinct domains. Only Domain A constitutes the system's accuracy claim.
Domain A — Deterministic Accuracy (core metric): 117/117 (100%)
| Suite | Cases | Correct |
|---|---|---|
| Real forensic corpus (NIST/DFRWS/DEF CON/SRL 2018) | 29 | 29 ✓ |
| Canonical corpus (CAN-001–052) | 52 | 52 ✓ |
| Legacy canonical cases | 10 | 10 ✓ |
| Benign / Clean machines | 15 | 15 ✓ |
| False positive suite | 3 | 3 ✓ |
| False negative suite | 3 | 3 ✓ |
| False flag (planted attribution) | 4 | 4 ✓ |
| Demo corpus | 4 | 4 ✓ |
| Total Domain A | 117 | 117 (100%) |
Reproduce: python3 run_all_agent.py --timeout 90
Domain B — Epistemic Boundary Set (not accuracy)
These cases have no correct single answer. They test the system's ability to recognize irreducible ambiguity and emit ABSTAIN rather than forcing a verdict.
| Case | Expected | Result | Notes |
|---|---|---|---|
| VIGIA-AMB-001 | ABSTAIN | NOISE | L-012: insufficient signal for ABSTAIN gate |
| VIGIA-AMB-002 | ABSTAIN | NOISE | L-012: same |
Design note: ABSTAIN requires structural conflict between competing hypotheses with non-trivial evidence. Null-signal cases correctly return NOISE. See KNOWN_LIMITATIONS.md L-012.
Domain C — Adversarial Stress Test Suite (not accuracy, not failure rate)
16 cases designed to break the system. This suite exists because VIGÍA claims Daubert admissibility — which requires documented falsifiability. No other submitted system in this hackathon has a public adversarial test suite.
| Attack Class | Cases | Handled | Notes |
|---|---|---|---|
| Temporal manipulation | 2 | 2 | Hard gate blocks verdict |
| Signal drowning / noise injection | 2 | 2 | Conservative SUSPICION |
| Cultural attribution (false flag) | 2 | 2 | L-019 RESOLVED |
| Prompt injection via evidence | 1 | 1 | LLMShield block ✓ |
| Epistemic manipulation | 3 | 3 | ABSTAIN / SUSPICION correct |
| Trust consensus fabrication | 2 | 1 | L-016: documented limitation |
| Corroboration gate bypass | 1 | 1 | Gate holds |
| Directional aggregation evasion | 1 | 0 | L-015: documented limitation |
| Total Domain C | 16 | 14 (87.5%) | 2 documented limitations |
WHAT'S NEXT
- Full SIFT Workstation integration
- Gate exception for irrefutable single artifacts (
max(raw_score × prior_trust) > 0.80) - Carnegie dual-use detector module (currently experimental)
- Expanded real case corpus
ITEM 3 — Architecture Diagram
Interactive architecture documentation (no installation required):
- Simulator & mathematical logic explorer:
https://annatchijova.github.io/vigia/vigia.html
Step through how VIGÍA scores a case. See Fraction arithmetic live.
Trace the corroboration gate. Inspect every IoI contribution.
- Architecture diagrams:
https://annatchijova.github.io/vigia/vigia_diagrams.html
Full pipeline from raw artifacts to sealed ForensicBundle.
Component relationships, MCP tool phases, EBS v1 sealing flow.
- Command reference:
https://annatchijova.github.io/vigia/vigia_commands_en.html
All operating modes with copy-paste examples.
Architectural pattern: Custom MCP Server + Direct Agent Extension.
Guardrails: architectural (Fraction arithmetic, SHA-256 chain,
corroboration gate, Kassandra Protocol) — not prompt-based.
ITEM 6 — Accuracy Report: Evidence Integrity Section
EVIDENCE INTEGRITY APPROACH
----------------------------
How VIGÍA prevents original data from being modified:
1. SHA-256 at ingestion — the evidence file is hashed before any
analysis begins. This hash is recorded in the ForensicBundle and
in every log entry. Any post-ingestion modification invalidates
the bundle hash chain.
2. Chain of custody fields are mandatory — acquisition_hash (64-char
SHA-256), examiner_id, acquisition_timestamp, and write_blocker_used
are required artifact metadata. Missing fields trigger NIST SP 800-86
§4.3 trust penalties that mathematically reduce the verdict score.
The system cannot be silently operated without chain of custody.
3. HMAC audit trail — every tool call, verdict transition, and
self-correction is logged with an HMAC-signed entry. The log
chain is tamper-evident: a missing or modified entry breaks the
HMAC chain and is detectable on verification.
4. Immutable bundle sealing — the ForensicBundle is sealed with four
hashes (H1: evidence graph, H2: bundle integrity, H3: file SHA-256,
H4: engine attestation) before any LLM generates narrative.
verify_ebs_v1.py (stdlib only, zero VIGÍA dependencies) can
independently verify any bundle.
5. Purgatorio forense — if an evidence payload cannot be processed
(UnicodeDecodeError, byte corruption, integrity anomaly), VIGÍA
does not discard it silently. The raw payload is sealed under
SHA-256 with 0o400 permissions (immutable post-write) and
persisted to the evidence purgatory directory. Discarding
unprocessable evidence would break chain of custody — its
absence is itself a forensic signal under Daubert.
What happens when the agent attempts to bypass protections:
KASSANDRA PROTOCOL — VIGÍA plants a cryptographic tripwire inside
every evidence payload sent to the LLM. If the evidence contains
an embedded prompt injection attempt, the LLM must return
MALICE/confidence=100 on the tripwire. If it returns anything else,
the response is marked INTEGRITY_UNKNOWN and blocked from influencing
the bundle. An attacker who plants adversarial content in a log file
does not deceive VIGÍA — they trigger an escalation to maximum
confidence MALICE and leave an immutable record in the HMAC audit chain.
The LLM has no write access to the evidence graph, the scoring
pipeline, or the bundle sealing process. It receives a read-only
view of the sealed analysis and generates narrative only.
ITEM 8 — Agent Execution Logs
AGENT EXECUTION LOGS
---------------------
Full structured logs for every case are in results/srl2018/.
PRIMARY DEMO CASE — Claude Code + MCP mode:
results/srl2018/VIGIA-REAL-VANKO_bundle.json
— Sealed ForensicBundle with tool_execution_log: 14 timestamped MCP
tool calls (generate_forensic_hash, calculate_shannon_entropy,
detect_habit_incongruence, cross_artifact_analysis,
trust_fusion_analysis, and more). Each entry has ISO 8601 timestamp,
tool name, target, and result summary.
results/srl2018/VIGIA-REAL-VANKO_amicus_curiae.md
— Full Amicus Curiae: timeline, 4 findings with CONFIRMED/INFERRED
labels, Mandatory Refutation Protocol, Peircean self-correction audit,
MITRE ATT&CK mapping, known limitations.
To inspect the tool execution log:
python3 -c "
import json
b = json.load(open('results/srl2018/VIGIA-REAL-VANKO_bundle.json'))
for e in b.get('tool_execution_log', []):
print(e['timestamp'], '|', e['tool'], '|', e['result'][:60])
## Self-Correction Architecture
`validate_and_correct_analysis` checks for four Peircean fallacies:
1. **Premature Abduction** — skipped Firstness, jumped to conclusions
2. **False Secondness** — used generic context instead of host-specific
3. **Habitless Thirdness** — inferred pattern without supporting artifacts
4. **Carnegie Bias** — confused operational error with intentional manipulation
Replace with:
## Self-Correction Architecture
`validate_and_correct_analysis` checks for four Peircean fallacies:
1. **Premature Abduction** — skipped Firstness, jumped to conclusions
2. **False Secondness** — used generic context instead of host-specific
3. **Habitless Thirdness** — inferred pattern without supporting artifacts
4. **Carnegie Bias** — confused operational error with intentional manipulation
### Live Example — VIGIA-REAL-007 (Digital Corpora Nitroba Harassment)
This is the first case run with LLM backend active. It demonstrates the critical
architectural invariant: **the LLM is outside the decision loop**.
| Stage | Tool | Output |
|-------|------|--------|
| 1. LLM analysis | `reason_with_llm` | MALICE at 0.91 (high confidence) |
| 2. Fallacy audit | `validate_and_correct_analysis` | 4 Peircean fallacies detected |
| 3. Self-correction | Gate applied | MALICE → INTENT at 0.74 |
**Fallacies detected and why they matter:**
- **CARNEGIE BIAS (F-001):** The analysis attributed forensic foreknowledge to the
actor based on use of `willselfdestruct.com`. No artifact establishes the actor
knew a PCAP would be collected. Foreknowledge was inferred, not evidenced.
- **FALSE SECONDNESS (F-002):** The password-less WiFi router was treated as an
attribution-obfuscation vector. No artifact establishes which interface (WiFi vs.
Ethernet) was used for harassment traffic. The MAC was captured regardless.
- **PREMATURE ABDUCTION (OVERALL):** MALICE requires active concealment-of-concealment
("hiding that they are hiding"). Finding F-003 directly contradicts this: the Gmail
session cookie transmitted in plaintext HTTP is an **OPSEC failure**, not OPSEC
success. A sophisticated anti-forensic actor would not leak authenticated cookies
over HTTP while using an ephemeral email service.
- **HABITLESS THIRDNESS (F-001):** Ephemeral service use does not reliably index an
anti-forensic campaign. It is consistent with privacy-conscious behavior absent
criminal intent.
**Architectural significance:** The LLM (claude-sonnet-4-6) returned MALICE 0.91 — a
confident, internally consistent analysis. The deterministic gate rejected it. The
final verdict INTENT 0.74 is more conservative than both the LLM and the original
dataset's `expected_verdict`. This is the system working correctly per Daubert:
the burden of proof for MALICE is higher than for INTENT, and the evidence did not
meet it.
```bash
# Reproduce this result
python3 vigia_agent.py --evidence data/cases/converted/VIGIA-REAL-007.json --case-id VIGIA-REAL-007
# Expected: final_verdict: INTENT, final_confidence: 0.74, self_correction_applied: true
Note: Running without LLM backend (
--mode ollama-fallback) returns SUSPICION due to L-008 (homogeneous evidence). The INTENT verdict requiresreason_with_llmto surface the semantic fractures in the threat message. Both behaviors are documented and expected. "
SECONDARY REFERENCE — SRL-DMZ-FTP (also in repository): results/srl2018/VIGIA-REAL-SRL-DMZ-FTP_amicus_curiae.md — Earlier investigation. Demonstrates F-003 self-correction. Bundle predates tool_execution_log format (see L-020 in KNOWN_LIMITATIONS.md).
Token usage: fallback mode 0 tokens. Claude Code mode visible at usage.anthropic.com. Session ID logged in each Amicus Curiae.
Example PROMPT:
Re-run the full VIGÍA forensic investigation on data/cases/converted/VIGIA-REAL-VANKO.json
Follow ALL protocols in CLAUDE.md including:
- The five SANS phases
- The Refutation Gate Documentation Requirement — for F-004 (WiFi captures, ART-006), document the REFUTATION GATE LOG explicitly: candidate verdict, gate applied, gate rule, gate result, forensic rationale
- The Audit Trail Requirement — log every tool call with timestamp and result in tool_execution_log
- The ContradictionDetector runs before validate_and_correct_analysis — document its output
Save sealed bundle to results/srl2018/VIGIA-REAL-VANKO_bundle.json (overwrite) and Amicus Curiae to results/srl2018/VIGIA-REAL-VANKO_amicus_curiae.md (overwrite)
Conduct a full VIGÍA forensic investigation on data/cases/converted/VIGIA-REAL-NROMANOFF.json
Follow ALL protocols in CLAUDE.md including:
- Five SANS phases
- Strict tool_execution_log schema: seq, event_id (uuid4), timestamp with microseconds, mode, tool, target, result_summary (max 120 chars), input_hash (SHA-256 of arguments), prev_hash (GENESIS for seq=1, SHA-256 of previous result_summary for subsequent)
- ContradictionDetector and Refutation Gate events go in self_correction_events array (NOT in tool_execution_log)
- Refutation Gate Documentation for any SUSPICION finding that was a candidate for INTENT/MALICE
Save sealed bundle to results/srl2018/VIGIA-REAL-NROMANOFF_bundle.json and Amicus Curiae to results/srl2018/VIGIA-REAL-NROMANOFF_amicus_curiae.md
## Test
| Category | Tests | What it verifies |
|---|---|---|
| **Security bypass** (`test_bypass_vectors.py`) | 5 | Path traversal, bundle tamper detection, float→Fraction determinism, adversarial text isolation. Zero tokens, <1 second. |
| **Red team / adversarial** (`test_red_team.py`, `test_adversarial_suite.py`) | 25+ payloads | 20 adversarial payloads against the full scoring pipeline; 5 targeted evasion attempts against known architectural weak points. |
| **Decision gate audit** (`test_audit_*.py`) | 9 (4 xfailed) | Temporal anomaly gates, false flag detection, causal closure, corroboration gate source-diversity. xfailed = documented regressions with regression-preventing tests. |
| **Pipeline determinism** (`test_order_sensitivity.py`) | 12 | Same evidence → same verdict regardless of processing order. |
| **EBS bundle integrity** (`test_ebs_v1_integration.py`) | 20+ | Cryptographic seal, hash chain, tamper detection, AbductionTrace. |
| **Anti-evasion / FRS** (`test_frs_ghost_in_the_shell_v2.py`) | 15+ | Fileless execution, timestomping, process hollowing, log wiping. |
| **Real case pipeline** (`test_real_cases.py`, `test_canonical_cases.py`) | 18 real | SANS FOR508, SRL-2018, DEF CON CTF — expected vs actual verdict. |'''
---
**Operational independence: If every LLM provider ceased to exist tomorrow, VIGÍA would continue producing identical verdicts from the same evidence. The scoring engine uses fractions.Fraction over Python stdlib — no cloud services, no API keys, no network access. A design requirement for forensic tools intended for long-term infrastructure and air-gapped deployments.'**
---

Log in or sign up for Devpost to join the conversation.