[BUG] security-guidance: pattern reminders never fire for NotebookEdit (new_source is not read)

Status Open
Reported on v2.1.289
Maintainer reply None cached
Activity 2 comments · opened Oct 5, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

The security-guidance plugin (2.0.0, plugins/security-guidance at 2bfb629) registers its PostToolUse hook for Edit|Write|MultiEdit|NotebookEdit (hooks/hooks.json:33). main() accepts NotebookEdit and reads notebook_path (security_reminder_hook.py:2112). patterns.py puts .ipynb in _PY_EXTS, so the Python rules are meant to cover notebooks.

extract_content_from_input() (security_reminder_hook.py:429-440) only handles Write (content), Edit (new_string) and MultiEdit (edits). For every other tool it returns "". NotebookEdit carries the cell text in new_source, so for a notebook edit no content-based rule runs: pickle, os.system, eval, yaml.load, torch.load and the others. The edit passes silently.

What Should Happen?

A NotebookEdit should be checked the same way as a Write of the same code. pickle.load(...) in a cell should produce the pickle_deserialization reminder through additionalContext.

Steps to Reproduce

Run the hook directly with synthetic PostToolUse input. Point HOME and SECURITY_WARNINGS_STATE_DIR at a scratch directory and pre-touch $STATE/.sdk_bootstrap_spawned so nothing is installed or spawned:

H=plugins/security-guidance/hooks/security_reminder_hook.py
S=$(mktemp -d); mkdir -p $S/state $S/proj; touch $S/state/.sdk_bootstrap_spawned
run() { HOME=$S SECURITY_WARNINGS_STATE_DIR=$S/state CLAUDE_PROJECT_DIR=$S/proj python3 $H; echo "exit=$?"; }

# 1. NotebookEdit with pickle.load in the cell -> no output
echo '{"session_id":"n1","hook_event_name":"PostToolUse","tool_name":"NotebookEdit","cwd":"'$S'/proj","tool_input":{"notebook_path":"'$S'/proj/a.ipynb","cell_id":"c1","new_source":"import pickle\ndata = pickle.load(open(p, \"rb\"))","edit_mode":"replace"}}' | run

# 2. Control: the same line via Edit on a .py file -> pickle reminder
echo '{"session_id":"n2","hook_event_name":"PostToolUse","tool_name":"Edit","cwd":"'$S'/proj","tool_input":{"file_path":"'$S'/proj/a.py","old_string":"x","new_string":"data = pickle.load(open(p, \"rb\"))"}}' | run

Actual:

  • Case 1 prints only exit=0.
  • Case 2 prints hookSpecificOutput.additionalContext with the pickle warning.

Suggested fix

elif tool_name == "NotebookEdit":
    return tool_input.get("new_source", "") or ""

With edit_mode: "delete", new_source is absent, so this stays a no-op.

Additional Information

  • Why it matters: notebooks are where pickle.load, torch.load and np.load(..., allow_pickle=True) are most common, so this is where the reminders matter most.
  • Searched first: I searched issues and PRs for security-guidance + NotebookEdit/notebook/new_source and found nothing. #87627, #83851, #85806 and #40172 are different security-guidance bugs.
  • Versions: Claude Code 2.1.289 (VS Code extension), Linux / WSL2. The bug is in the plugin script itself, so platform doesn't matter.
  • Disclosure: found while auditing with AI tooling; reproduced by hand with the commands above.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗