feat(memory): content scanning hardening + TOFU integrity framework for instruction files (closes #153, closes #154) - #237
Conversation
…nicode defense, rule extensions - Expand _MEMORY_BASENAMES from 2 to 7 + _MEMORY_GLOBS covering 9 agent rule directories matching the write-tripwire coverage set, plus recursive ** glob for copilot-instructions - Refactor _read_project_memory() into _discover_memory_files(), _read_memory_file() with _MEMORY_MAX_FILES=64 cap and report truncated/has_invisible_controls metadata - Add _instructions_loaded_paths() feature-detected consumer for InstructionsLoaded hook - Make _MEMORY_SCAN_LIMIT configurable via PRISMOR_MEMORY_SCAN_LIMIT env var - Add 14 bidi / invisible / Hangul filler codepoints to _CONFUSABLE_FOLD - Add _INVISIBLE_CONTROL_RE for structural invisible-character flagging - Extend memory-embedded-directive with 8 new patterns (authority assertion, tool policy override, system prompt override, suppression directives) - Add memory-exfil-directive (MEDIUM/warn, 5 patterns) - Add memory-tool-policy-override (HIGH/warn, 5 patterns) - Add memory-invisible-text (MEDIUM/warn, boolean-field on has_invisible_controls) - Add memory-oversized-instruction-file (LOW/warn, boolean-field on truncated) - Add _bool_field() helper to _extract_fields for metadata-to-field bridging - Add 16 new tests across test_policy_engine.py and test_unicode_evasion.py including structural invariants (filename superset, non-block category)
…cation (PrismorSec#154) - Add prismor/runtime/memory_guard.py: compute_file_hash, load_trust_store, verify_memory_files, trust/approve/sign/unsign helpers - Add .prismor/memory-trust.json trust store (per-workspace + global) - Add git-aware three-way classification (changed_in_commit / uncommitted / agent_session_change) with subprocess-timeout safety - Wire integrity check into hooks.py SessionStart path - Add memory-integrity-mismatch rule (warn, non-overridable, dynamic severity) - Extend PrismorSec#167 counter-instruction to cover integrity findings in cli.py - Add memory_integrity to _EVENT_SOURCE in policy_engine.py - Add prismor memory {status,trust,verify,scan,approve,sign,unsign} CLI - Add optional Ed25519 signed-memory mode (PRISMOR_MEMORY_SIGNED_MODE=1) - Add tests/test_memory_guard.py (18 tests, all passing) - Add docs/memory-integrity.md - Add scripts/verify-memory-guard.sh manual verification script Test results: 1,439 pass / 23 fail (baseline: 1,380) — +59 net new.
Review: TOFU integrity framework (#154 half of this PR) is disconnected from the real hook pathI checked out this branch, ran the test suite, and reproduced the SessionStart hook flow locally and on a separate test box (tampering with a committed 1.
|
…ing (review feedback) - hooks.py: fix dead-code bug — verify_memory_files() read from memory[_paths] which _read_project_memory() never sets; changed to memory[files] so integrity checks actually run at SessionStart. - runtime.py: bypass the regex rule engine for integrity findings — event[integrity_findings] is now merged directly into the findings list instead of depending on the never-produced integrity_warning field. - default_policy.yaml: remove fields: [integrity_warning] from memory-integrity-mismatch rule — field not produced by _extract_fields. - memory_guard.py: fix CRLF hashing mismatch in _classify_change by using subprocess.run(text=False) instead of _git() for the git-show call, matching compute_file_hash() which hashes raw bytes. All 192 tests pass.
|
Addressed all 4 review items from Ar9av: Critical 1 ✅ — Critical 2 ✅ — Integrity findings now bypass the regex engine entirely. Non-critical 3 — Noted. Trust-store write tripwire is a follow-up (separate PR). Non-critical 4 ✅ — CRLF hashing mismatch fixed. All 192 tests pass ( |
Summary
This PR hardens Prismor's defense against memory poisoning (ASI06 – Memory & Context Poisoning) with two complementary layers:
Content scanning hardening (CLAUDE.md/AGENTS.md content is read but never scanned for embedded directives (memory-poisoning bypass) #153): expands scanned filenames from 2 to 11 basenames + 9 globs (matching the write-tripwire coverage), adds bidi Unicode defense against Trojan Source / CVE-2021-42574 attacks, and extends detection patterns from 8 to 26 patterns across five rules.
Integrity framework (No integrity/provenance check on CLAUDE.md/AGENTS.md — a poisoned file at session start is trusted the same as reviewed content #154 — the durable fix): adds trust-on-first-use (TOFU) SHA-256 baselines with git-aware change classification so an agent can tell whether an instruction file "changed in a human-reviewed commit" vs "was modified by uncommitted local edits" vs "was written by an agent tool call in the same session." Integrity findings feed the existing SessionStart counter-instruction so the model itself treats unverified changes as untrusted.
Background
Agent auto-load instruction files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) are authority surfaces without authentication. The TrapDoor campaign (Socket, May 2026) planted 34+ packages that installed persistence through .cursorrules and CLAUDE.md; the attacker opened PRs against browser-use, langchain, llama_index, MetaGPT, and OpenHands adding poisoned instruction files with hidden bidirectional Unicode text. This PR addresses the ASI06 (Memory & Context Poisoning) gap in Prismor's coverage.
Changes
Content scanning (#153)
CLAUDE.md,AGENTS.md) to 11 basenames + 9 globs covering.cursorrules,.cursor/rules/*.mdc,.claude/rules/*.md,GEMINI.md,.windsurfrules,.github/copilot-instructions.md,CLAUDE.local.md,.claude/agents/*.md, and more — aligned with the write-tripwire coverage_CONFUSABLE_FOLD: LRE, RLE, PDF, LRO, RLO, LRI, RLI, FSI, PDI, line/paragraph separators, Hangul/Mongolian/Braille fillersmemory-embedded-directiveextended with 8 new patterns (authority assertion, tool policy override, system prompt override, suppression directives)memory-exfil-directive(MEDIUM),memory-tool-policy-override(HIGH),memory-invisible-text(MEDIUM),memory-oversized-instruction-file(LOW) — all warnPRISMOR_MEMORY_SCAN_LIMITenv var (default 64KB, range 4KB-4MB)Integrity (#154)
prismor/runtime/memory_guard.py— TOFU SHA-256 baseline store, git-aware change classification, Ed25519 signed-memory mode (optional).prismor/memory-trust.jsonper-workspace with global fallbackchanged_in_commitvsuncommitted_changevsagent_session_changevsunclassified_changevsfile_removedprismor memory {status,trust,verify,scan,approve,sign,unsign}warn;memory_integrityis not in_CORE_BLOCK_CATEGORIESTest Results
The 23 pre-existing failures (test_staged_execution, test_workspace_scope, test_receipt_signing, etc.) are unchanged from the baseline.
Verification (for reviewer)
Files Changed
prismor/runtime/hooks.pyprismor/runtime/policy_engine.py_CONFUSABLE_FOLDadditions (14 codepoints),_NON_OVERRIDABLE_RULE_IDS,_EVENT_SOURCEprismor/runtime/default_policy.yamlmemory-embedded-directive, 4 new rules,memory-integrity-mismatchprismor/runtime/cli.pyprismor memorysubcommandprismor/runtime/memory_guard.pytests/test_policy_engine.pytests/test_unicode_evasion.pytests/test_memory_guard.pydocs/memory-integrity.mdscripts/verify-memory-guard.shCommit Structure
5d51dbf—feat(memory): content scanning hardening — expanded filenames, bidi Unicode defense, rule extensions9906704—feat(memory): TOFU integrity framework with git-aware change classification (#154)References