Skip to content

PreToolUse guard remediation: scratch-root default, kill-switch hoist, MCP coverage, two conventions #3719

Description

@kyle-sexton

Tracking issue for the actionable half of the PreToolUse guard audit, under the contract locked in
that topic's PLAN.md. The topic's contract slice (docs/topics/claude-pretool-validation-hooks-84d7ka/,
carrying PLAN.md and the 484-line FINDINGS.md) was pruned before merge per the topic-docs
convention. Best-effort retrieval while GitHub retains the object — pre-prune commit
19318ff1ba9c5af12a93f34332f0468004c12c27:

gh api "repos/melodic-software/claude-code-plugins/contents/docs/topics/claude-pretool-validation-hooks-84d7ka/FINDINGS.md?ref=19318ff1ba9c5af12a93f34332f0468004c12c27" --jq .content | base64 -d

The locked Brief is reproduced verbatim in the body of #3727.

The 17 PreToolUse guards had never been audited against the current model generation or the current
hooks reference. The audit's ablation verdicts turned out to be its least actionable part; what it
found that was actionable is below.

Scope

  1. block-hook-bypass fires with zero true positives on write targets it should never have
    blocked.
    block_hook_bypass_scratch_roots shipped empty, so the harness's own per-session
    scratchpad blocked. Measured at five blocks in one day across four sessions with no true positive.
    Per ADR 0003 clause 4 this is a wrong SCOPE rather than a wrong oracle, so the remedy is rescoping,
    not deletion. (The memory tier .work/ was originally in this scope and was withdrawn in review
    on fix(hooks): PreToolUse guard remediation — scratch-root default, kill-switch hoist, MCP coverage, two conventions #3727: exempting it reopened a content-guard bypass. See session-flow prescribes a write command guardrails blocks #3720 and secret-pattern-detection scans the memory tier, which the topic-docs convention designates for raw credentials #3730.)

  2. Every guard's kill switch is read after the library it costs. All 17 read <name>_enabled
    through hook::check_enabled, which only exists once the 2,684-line hook-utils.sh is sourced,
    so a DISABLED guard parses the whole library before finding out it has nothing to do.
    scripts/sync-hook-utils.sh covers the vendored library copies but not the entry scripts, so
    nothing would notice the ordering drifting back.

  3. Two one-line visibility fields are missing. Both disk-hygiene PreToolUse rows lack a
    statusMessage while its Stop row has one; and all 20 plugins/*/hooks/hooks.json omit the
    documented optional top-level description.

  4. The content guards have an MCP blind spot. secret-pattern-detection and
    hardcoded-path-check match Write|Edit|NotebookEdit only, so a session can be cleared by both
    and still push the same secret to a repository through mcp__github__push_files or
    mcp__github__create_or_update_file — a route with no local file to fix afterwards and no
    pre-commit content-invariants layer on it.

  5. Two policy questions have no written home, and were being re-litigated: whether a plugin's
    hooks may be split out of it, and whether a PreToolUse hook may silently rewrite a tool call.

Out of scope

Recorded here so the boundary is explicit rather than implied:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions