A local verification script got blocked with "Piping fetched output", "code you have
never seen", and a curl -o remedy. There was no URL, no fetch, and the bytes came from a
quoted heredoc that is fully visible in the command. The deny is correct and stays. Only the explanation
changes.
| pipe target | rule | source |
|---|---|---|
sh bash zsh dash tclsh | deny ALWAYS | a shell runs stdin as a script |
python3 node perl ruby | deny only with a network source | #3096 carve-out |
The quote walker tracks ' and " but
has no heredoc awareness, so I expected cat <<'EOF' > file containing a
| bash line to false-positive. It does not. Driving the shipped alpha.19 bundle through
run-hook.mjs:
curl piped to bash deny correct LOCAL cat piped to bash deny correct, by design local data to python3 allow #3096 intact heredoc written to a FILE containing | bash allow no false positive the reported shape (heredoc into source) allow does NOT reproduce false positives: 0
Two conclusions. The detector needs no change. And since the reported shape allows, the real command must have held a genuine unquoted pipe to a shell, so the block was right. That reduced the fix from "detector plus message" to message only.
PipeToInterpreterKind 'exec' | 'interpreter'
-> 'exec' | 'exec-local' | 'interpreter'
both still DENY. the source now only selects the reason.
States the real cause (a shell runs stdin as a script, so origin is irrelevant), says plainly that nothing
was fetched, and redirects to a real argv: write the body to a file, then bash /tmp/script.sh.
It also points at the still-allowed shape for local data, cat f | python3 -c ....
new test vs PRE-FIX code (blocker stashed) FAILS not vacuous new test vs this branch 5 passed typecheck 0 full hook suite exit 0 (captured, never through a pipe) validate-counts / manifests / security 0
Why the control matters here. A test written after a fix usually passes for the wrong
reason. Stashing only dangerous-command-blocker.ts and re-running proves the assertions can
observe the defect. The suite exit code is captured directly rather than read through
| tail, which returns tail's status and would report success over a failing run.