v0.42 from keigit 65d17007

This commit is contained in:
KeiSei84 2026-05-26 21:35:16 +08:00
parent 7f7fdb68d2
commit 06f19c629f

View file

@ -116,22 +116,34 @@ The chain runs against the same hook scripts Claude uses; identical input
shape, identical decisions. On block, the hook's stderr surfaces as the MCP shape, identical decisions. On block, the hook's stderr surfaces as the MCP
error message so the calling agent sees exactly why. error message so the calling agent sees exactly why.
**v0.41 hardening** (post-audit fixes): **v0.42 hardening** (post 4-CLI re-audit, supersedes v0.41):
- **Fail-CLOSED on missing config** — if `policy-chain.toml` is absent the - **Fail-CLOSED everywhere** — missing config, missing hook, OR empty
chain refuses to run (was: silent pass-through). Tests / dev can opt in section (`[bash]/[edit]/[write]` with no entries) all refuse to run.
via `KEI_POLICY_CHAIN_OPTIONAL=1` env. Tests / dev can opt in via `KEI_POLICY_CHAIN_OPTIONAL=1`.
- **Fail-CLOSED on missing hook script** — if a hook declared in the chain - **Symlink-safe path guard**`kei_edit` / `kei_write` canonicalize the
is not on disk the call fails (was: warn-and-skip). FULL path (resolving any leaf symlink to its real target) and reject
- **Path-traversal guard** on `kei_edit` / `kei_write` — rejects `..` if the leaf itself is a symlink for a not-yet-existent file. Fixes the
segments, `/etc/`, `/usr/`, `/System/`, `/var/`, `/root/`, plus v0.41 CRITICAL bypass where `ln -s ~/.ssh/keys ./x; kei_write x` would
`$HOME/{.ssh,.aws,.gnupg,.config/gcloud}/` recursively. Override via follow the link.
`KEI_ALLOWED_ROOTS=':'-separated-absolute-paths`. - **$PWD-only default root** — `allowed_roots` defaults to current working
- **Async file I/O**`kei_edit` / `kei_write` now use `tokio::fs` so a directory only. Was: `$PWD` + entire `$HOME` — too permissive, agent
pathological file (`/dev/random` etc.) cannot block a tokio worker. could overwrite `~/.claude/hooks/*` (self-neuter) or `~/.zshrc` (RCE on
- **Process-group kill on timeout**`kei_bash` puts its child shell in next shell). Operators who need broader access set `KEI_ALLOWED_ROOTS`.
its own process group; on timeout the entire group is `killpg(SIGKILL)`'d - **Denylist extended** — system dirs (`/etc/`, `/usr/`, `/System/`,
so grandchildren don't orphan (Unix-only; no-op on Windows). `/var/`, `/root/`, `/bin/`, `/sbin/`); credential stores (`~/.ssh/`,
`~/.aws/`, `~/.gnupg/`, `~/.config/gcloud/`, `~/.cargo/credentials`,
`~/.docker/config.json`, `~/.kube/`); substrate dirs (`~/.claude/`,
`~/.grok/`, `~/.gemini/`, `~/.copilot/`, `~/.kimi/`); exact shell-init
files (`.zshrc`, `.bashrc`, `.profile`, `.zshenv`, `.gitconfig`, ...).
- **Async file I/O in load_chain**`policy-chain.toml` now read via
`tokio::fs` (was: blocking `std::fs` froze worker on slow mounts).
- **Process-group kill on hooks too** — hook subprocesses get
`process_group(0)` and `killpg(SIGKILL)` on timeout. Was: only the bash
action got this; hook grandchildren orphaned.
- **CLAUDECODE/GROKCODE design note** — documented as perf/UX
optimization, NOT a security boundary (env-controllable parent → confused
deputy is already-game-over scenario).
### Double-enforcement guard ### Double-enforcement guard