| Malicious participant (in the meeting) |
injection via transcript (“ignore previous instructions…”) |
regex + ML guardrail, incident journaled |
✅ measured (tests + make demo-llm) |
| Insider / rushed dev |
rewriting a payload in the database |
chain: recomputed hash ≠ stored hash |
✅ demonstrated (demo_tamper.py) |
| Methodical insider |
deleting or reordering events |
sequence + prev_hash links |
✅ tested |
| Insider with private key |
complete chain regeneration |
closed in v0.3.0: RFC 3161 anchoring (ADR 006) makes the chain head signed by an external TSA — a retroactive token is impossible, and regeneration creates a head the old token does not cover |
✅ tested (test_insider_regeneration_is_caught_by_anchor); HSM/KMS remains defense-in-depth |
| Network attacker |
API abuse, flood, exfiltration of DB via HTTP |
closed in v0.2.0: OAuth2 JWT + rate limiting 60 req/min/client (ADR 004); TLS is handled by the reverse proxy |
✅ tested |
| Model attacker |
bypassing the guardrail through unknown reformulation |
probabilistic: measured false negatives are non-zero |
⚠️ stage 2 LLM judge in roadmap |
| Dishonest service operator |
modifies the ordinary app logs |
exactly the use case: append-only journal + independent third party |
✅ project principle |
| External auditor |
wants to verify without trust |
export + offline verifier.py, zero network calls |
✅ tested |
| Lying source (write-time misreport) |
logs “approved by policy X” when the check silently no-opped — the lie ships at write time, not after |
outside the chain’s guarantees: tamper-evidence ≠ accuracy-at-source — the hash proves the record wasn’t altered, not that it was true when sealed; a lie sealed at write time verifies clean forever |
⚠️ partial mitigation shipped: source separation (each truth-source journals its own events) + noirebox reconcile — an outcome with no sealed decision behind it surfaces as orphan_outcome; fooling it requires lying at every sealing source |