Context
PR #808 (commit f93e6e40) landed the capture-campaign installer scripts in-repo at pact-plugin/tests/runbooks/install_logging_shim.sh and install_taskcompleted_logging_shim.sh. Live install during the capture experiment revealed a cross-session capture leak that the installer design does not currently guard against.
Empirical failure mode
When the installer modifies a hook file at ~/.claude/plugins/cache/pact-plugin/PACT/<version>/hooks/<event>.py, the modification applies to that hook file globally on the machine. Every Claude Code session using that plugin version invokes the shimmed hook on every fire.
During PR #808's capture experiment, the TaskCompleted shim captured a fire from a parallel "reflectica" Claude Code session on the same machine — NOT our PACT development session. Empirical evidence: 1 of 3 captures had session_id: 3655e8cc-... (not our 7642b0c9-... session).
Privacy + scope concerns
- Privacy: captures contain
task_description (free-text), cwd (path fingerprint), session_id (correlatable across captures), transcript_path (filesystem path), and full tool I/O for PostToolUse. A user running the shim for one session's debug accidentally captures stdin from ANY concurrent session.
- Forgotten installs: nothing currently auto-uninstalls the shim. If the installer runs and the operator forgets the manual
cp .preshim.bak hook.py uninstall step, the shim keeps capturing indefinitely for ALL future sessions on this machine.
- Cross-user surface: on shared machines (multi-tenant Mac, dev container with multiple users), one user's shim install affects all other users' sessions.
Current safety surface (insufficient)
.preshim.bak backup file is created (operator can restore)
- Try/except: pass in shim Python (no behavioral impact if shim errors)
- Idempotency check prevents double-install
- Marker comment in hook file (
PACT-PREPARER-LOGGING-SHIM-INSTALLED) makes installs visible to grep
None of these prevent cross-session capture or enforce uninstall.
Proposed mitigations (graduated)
Tier 1 — Documentation hardening (cheap)
- Add a prominent "⚠️ DEVELOPMENT USE ONLY" banner to both installer scripts + the in-repo runbook (
pending-scan-dogfood.md or a new shim-install-runbook.md).
- Add an explicit warning that captures contain stdin from ALL concurrent Claude Code sessions on the machine.
- Make the uninstall command the LAST thing the installer prints (already does — make it more prominent).
- Document a recommended workflow: install → run capture session → IMMEDIATELY uninstall → THEN promote captures to fixtures.
Tier 2 — Session-scoping (medium)
- Modify the shim to FILTER captures by session_id BEFORE writing: read the installing-session's session_id at install time, embed it as a constant in the shim, and only capture stdin payloads whose
session_id matches.
- Concrete sketch:
# In install_taskcompleted_logging_shim.sh, at install time:
INSTALLING_SESSION_ID = $(grep -oE 'session_id: [a-f0-9-]+' \"$HOME/.claude/projects/...latest-jsonl\" | head -1)
# Embedded in shim Python:
shim_template = '''
import json as _shim_json
_SHIM_SCOPED_SESSION_ID = \"__SCOPED_SESSION_ID_LITERAL__\"
try:
_shim_buffer = _shim_sys.stdin.read()
_shim_data = _shim_json.loads(_shim_buffer) if _shim_buffer else {}
if _shim_data.get(\"session_id\") == _SHIM_SCOPED_SESSION_ID:
# only capture our session's fires
...write capture...
# Always replay stdin so the hook still works
_shim_sys.stdin = _shim_io.StringIO(_shim_buffer)
except Exception:
pass
'''
Tier 3 — Auto-uninstall (heavy)
- Wire the shim install lifecycle into PACT session-end:
/PACT:wrap-up or session-end hook checks for installed shims and uninstalls them.
- Add a
pact-plugin/tests/runbooks/uninstall_*_shim.sh companion script (currently the uninstall is one-line cp instructions in the install script's output).
- Track installed-shim state in
~/.claude/teams/<team>/shim-state.json so PACT knows what's installed and can clean up.
Recommended initial scope
Tier 1 (immediate) + Tier 2 (medium effort, high value). Tier 3 (heavy) deferred to follow-up.
Acceptance criteria
Cross-refs
Severity
type: security (privacy class, not auth boundary — same-machine same-user threat model; foot-gun protection rather than adversarial-boundary). priority: high because the installer scripts are now in-repo and discoverable; without hardening, any contributor running them risks the same leak.
Context
PR #808 (commit
f93e6e40) landed the capture-campaign installer scripts in-repo atpact-plugin/tests/runbooks/install_logging_shim.shandinstall_taskcompleted_logging_shim.sh. Live install during the capture experiment revealed a cross-session capture leak that the installer design does not currently guard against.Empirical failure mode
When the installer modifies a hook file at
~/.claude/plugins/cache/pact-plugin/PACT/<version>/hooks/<event>.py, the modification applies to that hook file globally on the machine. Every Claude Code session using that plugin version invokes the shimmed hook on every fire.During PR #808's capture experiment, the TaskCompleted shim captured a fire from a parallel "reflectica" Claude Code session on the same machine — NOT our PACT development session. Empirical evidence: 1 of 3 captures had
session_id: 3655e8cc-...(not our7642b0c9-...session).Privacy + scope concerns
task_description(free-text),cwd(path fingerprint),session_id(correlatable across captures),transcript_path(filesystem path), and full tool I/O for PostToolUse. A user running the shim for one session's debug accidentally captures stdin from ANY concurrent session.cp .preshim.bak hook.pyuninstall step, the shim keeps capturing indefinitely for ALL future sessions on this machine.Current safety surface (insufficient)
.preshim.bakbackup file is created (operator can restore)PACT-PREPARER-LOGGING-SHIM-INSTALLED) makes installs visible to grepNone of these prevent cross-session capture or enforce uninstall.
Proposed mitigations (graduated)
Tier 1 — Documentation hardening (cheap)
pending-scan-dogfood.mdor a newshim-install-runbook.md).Tier 2 — Session-scoping (medium)
session_idmatches.Tier 3 — Auto-uninstall (heavy)
/PACT:wrap-upor session-end hook checks for installed shims and uninstalls them.pact-plugin/tests/runbooks/uninstall_*_shim.shcompanion script (currently the uninstall is one-linecpinstructions in the install script's output).~/.claude/teams/<team>/shim-state.jsonso PACT knows what's installed and can clean up.Recommended initial scope
Tier 1 (immediate) + Tier 2 (medium effort, high value). Tier 3 (heavy) deferred to follow-up.
Acceptance criteria
uninstall_*_shim.shcompanion scripts land inpact-plugin/tests/runbooks/.Cross-refs
f93e6e40)Severity
type: security(privacy class, not auth boundary — same-machine same-user threat model; foot-gun protection rather than adversarial-boundary).priority: highbecause the installer scripts are now in-repo and discoverable; without hardening, any contributor running them risks the same leak.