fix(guards): close interpreter and lexical bypasses on H-05/H-11/H-18/H-22 - #615
Merged
Conversation
…/H-22 H-05/H-11/H-18 carried no interpreter leg at all: an inline-code one-liner (python3 -c, py -c, pwsh -Command) walked past every filesystem-verb and redirect check on the audit logs, ADRs under decisions/, and CONTEXT.md, even though H-19/H-22 already closed the identical gap for gate markers and the protected-state registry. LOG_INTERP_RE/DECISIONS_INTERP_RE/ CONTEXT_INTERP_RE take H-19's token-only shape (no inline-code requirement, since none of the three have H-22's sanctioned interpreter caller to spare) (#574). H-22's git-restore leg matched only a registered file's bare basename, so restoring the file's ENCLOSING DIRECTORY (git checkout HEAD -- .codearbiter/) rewrote every enrolled file while naming none of them. git_restore_re now gains one alternative per ancestor directory, precisely anchored so it cannot swallow an unrelated sibling file. In the other direction, a package manager's `install` SUBCOMMAND (pip install, npm install, cargo install, ...) was false-blocked by the write-verb leg built for coreutils' `install`; _strip_pkg_manager_install narrows this via a preceding-token check before the verb-list regex runs (#575). The Codex host notes' hook-safe audit-log append recipe directed Windows PowerShell 5.1 users to bare `>>`, which can write a UTF-16LE tail onto an existing UTF-8 log (NUL bytes, forcing a destructive H-05 override to repair). The recipe now uses an explicit UTF-8-no-BOM [System.IO.File]::AppendAllText append, with a documented NUL-byte verification step; the replacement stays guard-transparent (no powershell/pwsh sub-invocation token on the line, so it doesn't trip the new H-05 interpreter leg either) (#594). Every closed bypass is pinned by a red-before/green-after test: RED verified directly against the unfixed origin/main guard module before each fix, GREEN against the patched module after. Full guard-matrix suites (.github/scripts/test_hook_guards.py, test_hooklib.py) and the plugins/ca/hooks/tests pytest suite both pass with no regressions to the existing guard matrix (1318 passed / 149 subtests, vs. baseline's 1301 / 130 — 10 pre-existing worktree-root-family failures unchanged, unrelated to this change). Version advance: ca 2.11.7 -> 2.11.9, ca-codex 0.4.6 -> 0.4.8, ca-pi 0.2.6 -> 0.2.8 (root package.json regenerated). CHANGELOG: H-05/H-11/H-18/H-22 close interpreter and lexical shell-flank bypasses; the Codex PowerShell audit-log append recipe no longer risks UTF-16LE corruption. Claude-Session: https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
…74-575-594 # Conflicts: # CHANGELOG.md # README.md # package.json # plugins/ca-codex/.codex-plugin/plugin.json # plugins/ca-pi/CHANGELOG.md # plugins/ca-pi/package.json # plugins/ca/.claude-plugin/plugin.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three sev:med/sev:low security-guard-hardening findings from the workstream-B adversary pass, all STRENGTHENING existing guards (none weakens an enforcement surface):
#574 — H-05/H-11/H-18 had no interpreter leg at all
LOG_TRUNC_RE/LOG_DESTROY_RE(H-05, the.codearbiteraudit logs),DECISIONS_REDIRECT_RE/DECISIONS_WRITE_RE(H-11, ADRs underdecisions/), andCONTEXT_REDIRECT_RE/CONTEXT_WRITE_RE(H-18,CONTEXT.md) matched redirects and write verbs only — an inline-code one-liner (python3 -c "open('.codearbiter/overrides.log','w')...",py -c,pwsh -Command) walked past all three, even though H-19/H-22 already closed the identical gap for gate markers and the protected-state registry.LOG_INTERP_RE/DECISIONS_INTERP_RE/CONTEXT_INTERP_REclose it, built from the shared_INTERP_TOKENSconstant and taking H-19's token-only shape (interpreter token + target name anywhere on the line, no inline-code-switch requirement) — per the issue's own guidance, since none of the three has H-22's sanctioned interpreter caller (python3 "…/taskwrite.py" add -- "fix open-tasks.md schema") to spare from a narrower match.#575 — H-22 lexical residuals: directory restore miss, package-manager
installfalse-blockgit_restore_rematched only a registered file's bare basename, sogit checkout HEAD -- .codearbiter/restored the ENCLOSING DIRECTORY — rewriting every enrolled file through git while naming none of them — and never matched.git_restore_renow gains one alternative per ancestor directory of the registry entry'srel_path, precisely anchored (optional single trailing slash, then the same right-edge boundary the basename leg uses) so it matches only the directory itself, never a sibling file inside it.installis in_STATE_WRITE_VERBSfor coreutils'install(a genuine overwrite verb), but a package manager'sinstallSUBCOMMAND (pip install,npm install,cargo install,apt install,brew install, …) is a different verb wearing the same word — and the same-line write-verb window then reached a protected basename mentioned later on the line (a trailing comment), false-blocking a routine dependency install._strip_pkg_manager_installnarrows this via a preceding-token check (not a smarter parser): the known package-manager-subcommand spelling ofinstallis blanked out beforewrite_reruns, leaving the bare coreutils spelling untouched.#594 — Codex PowerShell audit-log append can write UTF-16LE tails
The Codex host notes' hook-safe append recipe directed Windows PowerShell 5.1 users to bare
>>against an existing UTF-8 audit log — PS 5.1's default redirection encoding is UTF-16LE, so the appended tail lands as UTF-16LE while the rest of the file stays UTF-8 (NUL bytes, forcing a destructive H-05 override to repair).core/surface/includes/codex-host-notes.mdnow recommends an explicit UTF-8-no-BOM[System.IO.File]::AppendAllTextappend plus a documented NUL-byte verification step. Confirmed the replacement stays guard-transparent: it's a plain PowerShell statement with nopowershell/pwshsub-invocation token on the line, so it does not trip the new H-05 interpreter leg from #574 either.Red/green proof table
python3 -cwrite tooverrides.log(H-05)[H-05]py -c/pwsh -Commandwrite tosprint-log.md/gate-events.log(H-05)[H-05]python3 -cwrite todecisions/0009-fake.md(H-11)[H-11]python3 -cwrite toCONTEXT.md(H-18)[H-18]git checkout HEAD -- .codearbiter/(H-22, directory restore)[H-22]pip install -r requirements.txt # then read open-tasks.md(H-22)[H-22](false positive)install -m 644 /tmp/forged .codearbiter/open-tasks.md(H-22, non-regression)Each row was verified directly against the unfixed
core/pysrc/_bashguardlib.pymodule loaded fromorigin/mainbefore implementing the fix, then re-verified against the patched module — the red-before/green-after IS the mutation proof, additionally pinned as permanent regression tests inplugins/ca/hooks/tests/test_protectedstatelib.py,plugins/ca/hooks/tests/test_pre_bash_activation.py, and.github/scripts/test_hook_guards.py.Test counts
plugins/ca/hooks/tests(pytest): 1318 passed, 149 subtests passed, 10 failed — identical 10 failures on unmodifiedorigin/main(confirmed viagit stash), the documented Worktree sessions: security-pass.py and H-09b/H-10b resolve different project roots — gate pass unrecordable #604 worktree-root family, unrelated to this change. Baseline was 1301 passed / 130 subtests passed / 10 failed — net +17 tests, +19 subtests, zero regressions..github/scripts/test_hook_guards.py: 190 assertions, 0 failed..github/scripts/test_hooklib.py: 94 tests, OK..github/scripts/test_release_trace.py: 29 tests, OK.Post-commit gates
check_badge_consistency.py: OKpayload_version_gate.py --plugin plugins/ca --base origin/main:2.11.7 -> 2.11.9, advancedpayload_version_gate.py --plugin plugins/ca-codex --base origin/main:0.4.6 -> 0.4.8, advancedbuild-host-packages.py --check --release-guard-base origin/main: Pi payload/version/changelog/root-metadata advanced together,0.2.6 -> 0.2.8check_site_voice.py: OKtools/sync-core.py --check/tools/build-surface.py --check: OKDeviations
.codearbiter/gate-events.logpicked up incidental BLOCK entries from my own manual in-process verification snippets during development (they ran against this real checkout instead of an isolated temp dir). H-05's owngit checkout-restore leg correctly refuses to let me discard them, and they're truthful (append-only, not fabricated), so they were left uncommitted/unstaged rather than force-reverted — not part of this PR's diff.plugins/ca-codex/CHANGELOG.mdentry: confirmed viapayload_version_gate.py's own docstring and the existing CHANGELOG (which already skips several point releases, e.g. 0.4.1–0.4.6 have no entries) that ca-codex's version gate checks manifest advancement only, not changelog presence — matching the task's explicit instruction to add a section only to the rootCHANGELOG.mdandplugins/ca-pi/CHANGELOG.md.Closes #574
Closes #575
Closes #594
https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB