fix(#1460): verify-or-reject capability --integrity per source; confine hook commands to the bundle

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-20 08:14:33 -04:00
parent 38e9b83178
commit 08d1c57d6e
9 changed files with 622 additions and 17 deletions

View File

@@ -0,0 +1,6 @@
---
type: Fixed
pr: 1481
---
**Capability `--integrity` is now verified or rejected per source, and hook commands are confined to the bundle** — a supplied `--integrity` pin was silently dropped for npm, git, and local capability sources (only the tarball source verified it), so a user could believe content was pinned when it was not. npm now verifies the pin over the `npm pack` `.tgz` bytes; git and local sources, which have no single hashable artifact, now reject a supplied `--integrity` with an actionable error instead of ignoring it. Separately, a capability hook's relative `script` was written verbatim as the hook command, so it resolved against the working directory (not the capability bundle) at hook-exec time and a crafted relative path could escape the bundle; the command is now resolved against the capability's own install dir and realpath-confined to it, then written as an absolute path. That absolute command is consumed by a shell, which exposed two further problems now fixed: (1) a manifest could ship a file literally named `run.sh; touch /tmp/pwn` (filenames may legally contain `;`, spaces, `$`, backtick, `|`, newline) and declare it as the hook `script`, so the emitted command injected a second shell command even though the file lived inside the bundle — the validator now rejects any hook script path outside a conservative `[A-Za-z0-9._/-]` allowlist (no whitespace, shell metacharacters, leading `-`, absolute path, or `..`), failing the install/load loudly, and the confinement helper mirrors the same rejection defensively; (2) the absolute path begins with the install-home directory, which commonly contains spaces (e.g. `/Users/Bob Smith/.claude/...`) and word-split or broke when written unquoted — the emitted command is now POSIX single-quoted so the install prefix can neither break nor inject. (#1460)