Skip to content

hotfix: scan only the prompt field from the hook stdin envelope - #45

Merged
fahadsiddiqui merged 1 commit into
mainfrom
hotfix/scan-prompt-field-only
Jul 22, 2026
Merged

hotfix: scan only the prompt field from the hook stdin envelope#45
fahadsiddiqui merged 1 commit into
mainfrom
hotfix/scan-prompt-field-only

Conversation

@fahadsiddiqui

Copy link
Copy Markdown
Member

Problem

Claude Code pipes a full UserPromptSubmit JSON envelope into the hook, but scripts/prompt-guard.js read stdin as if it were the bare prompt. Everything downstream operated on the raw JSON string.

Most visibly, redact mode handed back the whole envelope as the "cleaned copy you can paste instead":

---
{"session_id":"a24ce33f-…","transcript_path":"/Users/…/a24ce33f.jsonl","cwd":"/Users/…/otters","prompt_id":"c8320832-…","permission_mode":"default","hook_event_name":"UserPromptSubmit","prompt":"my email is <PII_1>"}
---

Fix

Added an extractPrompt(raw) helper that parses the stdin payload and scans only payload.prompt. It falls back to the raw text when stdin doesn't look like JSON or fails to parse, so the guard still scans something when the script is piped a prompt manually or if the protocol changes.

Redact mode now returns:

---
my email is <PII_1>
---

Secondary win: transcript_path, cwd and the envelope UUIDs are no longer scanned. They were a false-positive source across all three modes — capable of producing findings, inflating the risk score, and blocking prompts that contained no sensitive data of their own.

Tests

New tests/prompt-payload.test.ts spawns the real hook script against a realistic envelope:

  • redact mode returns the cleaned prompt and leaks no envelope keys
  • a clean prompt in a metadata-heavy envelope is allowed through
  • sensitive data inside the prompt field still blocks
  • non-JSON stdin falls back to a raw scan

Full suite: 351 passing, lint clean.

Notes

No dist/ change — the fix is in scripts/, which ships as-is, so the CI dist/ freshness check is unaffected.

Claude Code pipes a full UserPromptSubmit JSON envelope into the hook
(session_id, transcript_path, cwd, prompt_id, permission_mode,
hook_event_name, prompt), but scripts/prompt-guard.js read stdin as if it
were the bare prompt text. Everything downstream therefore operated on the
raw JSON string.

Changes:

- Add an extractPrompt(raw) helper to scripts/prompt-guard.js that parses
  the stdin payload and returns payload.prompt. Falls back to the raw text
  when stdin does not start with "{" or fails to parse, so the guard still
  scans something when the script is invoked manually with a piped prompt
  or if the hook protocol changes.
- Wire the helper into the stdin read path and expand the surrounding
  comment to explain why only the "prompt" field may be scanned or echoed.
- Fixes redact mode pasting back the entire JSON envelope instead of the
  cleaned prompt. The copy-pasteable block now contains just the redacted
  prompt text, e.g. "my email is <PII_1>".
- Fixes a false-positive source affecting all three modes: transcript_path,
  cwd and the various UUIDs in the envelope were previously scanned and
  could produce findings, inflate the risk score, and block prompts that
  contained no sensitive data themselves.
- Add tests/prompt-payload.test.ts with four end-to-end tests that spawn
  the real hook script against a realistic envelope: redact mode returns
  the cleaned prompt and leaks no envelope keys, a clean prompt with
  metadata-heavy envelope is allowed through, sensitive data inside the
  prompt still blocks, and non-JSON stdin falls back to a raw scan.

Full suite: 351 tests passing, lint clean.
@fahadsiddiqui
fahadsiddiqui merged commit f1376c1 into main Jul 22, 2026
3 checks passed
@fahadsiddiqui
fahadsiddiqui deleted the hotfix/scan-prompt-field-only branch July 22, 2026 20:52
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.

1 participant