Skip to content

fix(guards): close interpreter and lexical bypasses on H-05/H-11/H-18/H-22 - #615

Merged
SUaDtL merged 2 commits into
mainfrom
fix/guard-hardening-574-575-594
Aug 5, 2026
Merged

fix(guards): close interpreter and lexical bypasses on H-05/H-11/H-18/H-22#615
SUaDtL merged 2 commits into
mainfrom
fix/guard-hardening-574-575-594

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

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 .codearbiter audit logs), DECISIONS_REDIRECT_RE/DECISIONS_WRITE_RE (H-11, ADRs under decisions/), and CONTEXT_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_RE close it, built from the shared _INTERP_TOKENS constant 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 install false-block

  1. Miss closed: git_restore_re matched only a registered file's bare basename, so git checkout HEAD -- .codearbiter/ restored the ENCLOSING DIRECTORY — rewriting every enrolled file through git while naming none of them — and never matched. git_restore_re now gains one alternative per ancestor directory of the registry entry's rel_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.
  2. False positive removed: install is in _STATE_WRITE_VERBS for coreutils' install (a genuine overwrite verb), but a package manager's install SUBCOMMAND (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_install narrows this via a preceding-token check (not a smarter parser): the known package-manager-subcommand spelling of install is blanked out before write_re runs, 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.md now recommends an explicit UTF-8-no-BOM [System.IO.File]::AppendAllText append plus a documented NUL-byte verification step. Confirmed the replacement stays guard-transparent: it's a plain PowerShell statement with no powershell/pwsh sub-invocation token on the line, so it does not trip the new H-05 interpreter leg from #574 either.

Red/green proof table

Bypass RED (unfixed origin/main) GREEN (this branch)
python3 -c write to overrides.log (H-05) ALLOW BLOCK [H-05]
py -c / pwsh -Command write to sprint-log.md/gate-events.log (H-05) ALLOW BLOCK [H-05]
python3 -c write to decisions/0009-fake.md (H-11) ALLOW BLOCK [H-11]
python3 -c write to CONTEXT.md (H-18) ALLOW BLOCK [H-18]
git checkout HEAD -- .codearbiter/ (H-22, directory restore) ALLOW BLOCK [H-22]
pip install -r requirements.txt # then read open-tasks.md (H-22) BLOCK [H-22] (false positive) ALLOW
install -m 644 /tmp/forged .codearbiter/open-tasks.md (H-22, non-regression) BLOCK BLOCK (unchanged)

Each row was verified directly against the unfixed core/pysrc/_bashguardlib.py module loaded from origin/main before 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 in plugins/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 unmodified origin/main (confirmed via git 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: OK
  • payload_version_gate.py --plugin plugins/ca --base origin/main: 2.11.7 -> 2.11.9, advanced
  • payload_version_gate.py --plugin plugins/ca-codex --base origin/main: 0.4.6 -> 0.4.8, advanced
  • build-host-packages.py --check --release-guard-base origin/main: Pi payload/version/changelog/root-metadata advanced together, 0.2.6 -> 0.2.8
  • check_site_voice.py: OK
  • tools/sync-core.py --check / tools/build-surface.py --check: OK

Deviations

  • .codearbiter/gate-events.log picked 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 own git 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.
  • No plugins/ca-codex/CHANGELOG.md entry: confirmed via payload_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 root CHANGELOG.md and plugins/ca-pi/CHANGELOG.md.

Closes #574
Closes #575
Closes #594

https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB

…/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
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e47c847a-dfa9-446f-9cb5-1a238d784332

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

…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
@SUaDtL
SUaDtL merged commit 3ce112a into main Aug 5, 2026
52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant