Skip to content

RFC-023 hook bundle hardening#21

Merged
EsatanGW merged 6 commits into
mainfrom
rfc-023-hook-hardening
May 21, 2026
Merged

RFC-023 hook bundle hardening#21
EsatanGW merged 6 commits into
mainfrom
rfc-023-hook-hardening

Conversation

@EsatanGW
Copy link
Copy Markdown
Owner

Summary

  • Documents RFC-023 hook-bundle behavior and wiring layers.
  • Narrows risky-bash false-blocks for protected branch matching, .pem test fixtures, and common shell-init eval.
  • Makes consumer-registry network probing opt-in.
  • Narrows SQL/MCP destructive SQL matching so destructive verbs inside SQL string literals do not false-block.

Verification

  • Claude hook bundle selftests pass: 181 cases, 0 failed.
  • Codex/Cursor/Gemini/Windsurf adapter selftests pass: 4 cases, 0 failed each.
  • git diff --check passed.

Boundaries

  • No tag.
  • No release.
  • No Wave 5.
  • No memory update.

🤖 Generated with Claude Code

Abel and others added 6 commits May 21, 2026 13:44
…ave 1 manifest

Promote the Codex x Claude hook-audit consensus series (fixed point reached;
six owner decisions made) into a tracked Draft RFC, plus a schema-valid
Wave 1 (behavior-disclosure docs) Change Manifest draft.

Non-normative (docs/proposals/). No hook behavior change. Verified:
change-manifest schema clean, hook selftest 151/0, internal links 0 broken.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Clarify RFC-023 Wave 1 hook docs: Layer A vs Layer B wiring, network behavior, Stop and commit blockers, warn triggers, manifest discovery and Lean skip, and intentionally non-bypassable completion/evidence gates.

No hook behavior change; hooks/hooks.json, AGENTS.md, and docs/runtime-hook-contract.md are untouched.

Verification:

- reference-implementations/hooks-claude-code/selftests/selftest.sh -> 151 cases, 0 failed

- reference-implementations/hooks-{codex,cursor,gemini-cli,windsurf}/selftests/selftest.sh -> 4 cases, 0 failed each

- python3 .github/scripts/check-internal-links.py -> 0 broken

- make verify-local

- git diff --check

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Narrow risky-bash protected-branch force-push matching to refspec destinations, add the Bash tests/test .pem read exception, and allow only whitelisted shell-init eval command substitutions.

Verification: reference-implementations/hooks-claude-code/selftests/selftest.sh -> 176 cases, 0 failed; adapter selftests -> 4 cases, 0 failed each; python3 .github/scripts/check-internal-links.py -> ok no broken internal links across 310 markdown files; make verify-local -> OK; git diff --check -> clean.
Make the consumer-registry-check network probe opt-in: default-off skips the probe entirely, and the reachability check only runs when explicitly enabled. Adds the default-off-skips-probe fixture plus env fixtures for pass-reachable and warn-unreachable, and updates docs/DEVIATIONS/READMEs accordingly. Includes the Wave 3 Change Manifest.

Verification: hooks-claude-code selftest -> 177 cases, 0 failed; adapter selftests (codex/cursor/gemini-cli/windsurf) -> 4 cases, 0 failed each; validate-change-manifests.py -> OK in-flight schema clean; git diff --check -> clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@EsatanGW EsatanGW marked this pull request as ready for review May 21, 2026 16:10
@EsatanGW EsatanGW merged commit f2188ee into main May 21, 2026
16 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b8cf5a2d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +199 to +200
if printf '%s' "$sql_arg_masked" | grep -Eqi '(^|[[:space:];])UPDATE[[:space:]]+[a-zA-Z_."]+[[:space:]]+SET[[:space:]]+'; then
if ! printf '%s' "$sql_arg_masked" | grep -Eqi '\bWHERE\b'; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve identifier tokens when masking SQL for MCP checks

Using sql_arg_masked for the UPDATE ... SET / ALTER TABLE ... DROP patterns causes false negatives whenever table names are quoted identifiers (e.g. UPDATE "Users" SET ... or ALTER TABLE "Users" DROP COLUMN ...), because sql_mask_literals strips the quoted identifier text before matching. This regression lets destructive SQL through without AGENT_PROTOCOL_RISKY_MCP_ALLOW=1, which weakens the core safety block for production data-store mutations.

Useful? React with 👍 / 👎.

Comment on lines +184 to +186
if [ "$positional_index" -eq 1 ]; then
continue
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Treat first git-push positional token as possible refspec

The parser now unconditionally skips the first positional token after git push, but per git push syntax ([<repository> [<refspec>...]]) the repository is optional and that first token can be the refspec. As a result, commands like git push --force main (default remote, protected branch refspec) are no longer blocked, creating a force-push escape path for protected branches.

Useful? React with 👍 / 👎.

Comment on lines +166 to +167
[ "$token" = "git" ] && seen_git=1
continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Recognize path-qualified git executable in force-push parser

The new token parser only starts matching after a token exactly equal to git, so force pushes invoked as path-qualified binaries (for example /usr/bin/git push --force origin main) bypass Group 1 entirely. The prior implementation matched these forms, so this is a regression that allows protected-branch rewrites to pass without the expected block.

Useful? React with 👍 / 👎.

Comment on lines +483 to +484
cat|head|tail|less|more|grep|awk|sed|xargs|env|printenv|export)
after_read_verb=1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Match path-qualified read tools in PEM secret-read detection

.pem detection was moved out of cred_path into pem_read_outside_tests(), but that helper only treats bare command names (e.g. cat) as read verbs. Common path-qualified invocations like /bin/cat secrets.pem now evade blocking, whereas they were previously caught, reopening a credential-read bypass for PEM files outside test paths.

Useful? React with 👍 / 👎.

Comment on lines +349 to +350
exit 0
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Check all repeated -c SQL payloads for destructive verbs

dash_c_sql_payload() exits after the first -c argument, so commands that use repeated -c options (for example psql -c "select 1" -c "DROP TABLE users") are now treated as safe if the first payload is benign. psql executes -c options in sequence, so this change introduces a bypass for direct destructive database mutations that were previously blocked.

Useful? React with 👍 / 👎.

location="bash:tool_input.command"
hint="see docs/runtime-hook-contract.md §Risky-action interception list (defensive eval-or-pipe-sh group) and docs/destructive-action-discipline.md §3; download to a file, review it, then run — do not pipe network content into sh"
elif printf '%s' "$command_str" | grep -Eq '(^|[[:space:];|&])eval[[:space:]]+'; then
elif printf '%s' "$command_str" | grep -Eq '(^|[[:space:];|&])eval[[:space:]]+' && ! shell_init_eval_is_allowed; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Block commands that mix allowed init eval with arbitrary eval

The eval guard now blocks only when eval is present and shell_init_eval_is_allowed is false for the whole command line. That allows payloads like eval "$(direnv hook bash)"; eval "$UNTRUSTED" to pass, because one allowed init-eval suppresses blocking for subsequent arbitrary eval usage in the same command string.

Useful? React with 👍 / 👎.

@EsatanGW EsatanGW deleted the rfc-023-hook-hardening branch May 21, 2026 16:25
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