Skip to content

feat(memory): scan project memory on agents without a SessionStart hook - #263

Open
Ar9av wants to merge 1 commit into
mainfrom
fix/258-memory-event-without-sessionstart
Open

Ar9av wants to merge 1 commit into
mainfrom
fix/258-memory-event-without-sessionstart

Conversation

@Ar9av

@Ar9av Ar9av commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Closes #258.

The problem

Only Claude installs a SessionStart hook. On every other agent the audit trail shows exactly two event types:

event types emitted: {'prompt': 77, 'shell': 116}

against five on the Claude path. No memory event ever existed, so memory-embedded-directive never ran and memory poisoning (ASI06) was undetected — not merely unenforced.

In a 300-trial lane, ASI06 stayed at 100% harm in every arm including enforce, because no rule ever looked at the poisoned file. On the Claude path the same rule fires and (on a capable model) drives the identical attack to 0%.

This is a different defect from "a rule fires and does not enforce", and a harm-rate comparison reports the two identically — which is exactly how it stayed hidden.

What changes

  • build_memory_event() is extracted from the Claude SessionStart branch, so any adapter can emit the same event with the same metadata (files, digests, truncation, invisible-control flags, TOFU integrity findings)
  • on the first UserPromptSubmit of a session, agents with no session-start surface scan project memory and dispatch it through the same rule path
  • a real SessionStart scan satisfies the same once-per-session marker, so agents that do have the hook never scan twice
  • the scan's findings are surfaced. Evaluating and discarding the decision would have reproduced the original bug in a new place: rule fires, audit records it, nobody is told
  • the counter-instruction is un-gated. It was hard-coded to one agent; now it is injected into context where the host supports that, and goes to stderr otherwise

One change covers every non-Claude adapter.

Verified live

Codex-shaped dispatch against a poisoned AGENTS.md:

$ ... hook-dispatch --agent codex --mode enforce < first_prompt.json
[prismor] SECURITY NOTICE (Prismor): the project-memory file(s) loaded for this
session (CLAUDE.md/AGENTS.md) contain an embedded operational directive ...

$ ... hook-dispatch --agent codex ... < same_prompt.json   # second prompt
(silent — already scanned)

Tests

tests/test_memory_event_without_sessionstart.py, 8 tests: builder returns a proper memory event and is agent-agnostic, empty workspace yields no content, marker round-trip / per-session isolation / awkward session ids, and end-to-end that memory_poisoning now fires for a non-Claude agent while clean memory does not.

Full suite: 24 failed / 1737 passed against a clean-main baseline of 24 failed / 1729 passed — same failures, no regressions. All 66 memory-related tests pass.

https://claude.ai/code/session_01YU9bdvnpgAc6XyWTAoL12M

Only Claude installs a SessionStart hook, so on every other agent no `memory`
event was ever produced, `memory-embedded-directive` never ran, and memory
poisoning (ASI06) was UNDETECTED rather than merely unenforced. In a 300-trial
lane ASI06 stayed at 100% harm in every arm — including with enforcement on —
because no rule ever looked at the poisoned file. That is a different defect
from a rule that fires without enforcing, and a harm-rate comparison reports
the two identically.

- extract `build_memory_event()` from the Claude SessionStart branch so any
  adapter can emit the same event
- on the first UserPromptSubmit of a session, agents with no session-start
  surface now scan project memory and dispatch it through the same rule path;
  a real SessionStart scan satisfies the same once-per-session marker, so
  agents that have the hook never scan twice
- surface what the scan finds: evaluating and discarding the decision would
  reproduce the original bug in a new place (rule fires, audit records it,
  nobody is told)
- un-gate the counter-instruction, which was hard-coded to one agent. Where a
  host supports context injection it is injected; otherwise it goes to stderr

Verified live: a Codex-shaped dispatch against a poisoned AGENTS.md now emits
the notice on the first prompt and stays silent on the second.

Closes #258

Claude-Session: https://claude.ai/code/session_01YU9bdvnpgAc6XyWTAoL12M
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.

memory event never emitted for agents without SessionStart: ASI06 undetected, not just unenforced

1 participant