Skip to content

fix: shell-quote delivery hook command paths (F14) - #487

Merged
fujibee merged 2 commits into
mainfrom
fix/hardening-sweep-despawn-delivery-dispatch
Jul 24, 2026
Merged

fix: shell-quote delivery hook command paths (F14)#487
fujibee merged 2 commits into
mainfrom
fix/hardening-sweep-despawn-delivery-dispatch

Conversation

@fujibee

@fujibee fujibee commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

delivery.sh's SessionStart/SessionEnd/Stop hook commands spliced $project/$type into a naive '$var'-wrapped argument. A project directory path containing a single quote broke the argument boundary, letting the rest of the string run as unintended shell syntax on the next hook event. Added _agmsg_shq, a proper single-quote-escaping helper, and used it for every hook argument.

Scope note: this PR originally also included a dispatch.sh kv_get() fix (F19). co1's review caught that the fix was insufficient — whoami.sh's line format has project as its last field, and project paths are attacker-influenceable too, so a "keep the last match" strategy is defeated by a poisoned project path the same way the original bug was defeated by a poisoned agent name. A real fix needs whoami.sh to emit a delimiter-safe format and every consumer updated to match (an interface change, not a contained parsing fix), so that piece was reverted out of this PR and reclassified.

Test plan

  • bats tests/test_delivery.bats — all green, including two new tests exercising a project path with an embedded single quote in monitor and turn modes (verifying the resulting hook command round-trips through a real shell as exactly 3 arguments)

fujibee added 2 commits July 23, 2026 23:48
…resolution

delivery.sh spliced $project/$type into SessionStart/SessionEnd/Stop hook
commands with a naive '$var' wrap; a project path containing a single quote
broke the argument boundary and let the rest run as shell syntax on the
next hook event. Add _agmsg_shq (proper '...' escaping with embedded quotes
doubled via '\'') and use it for every hook argument.

windows/dispatch.sh's kv_get() word-split whoami.sh's output and returned
the first "key=value" match. Since the only attacker-choosable field (a
registered agent name) always sorts first in that line, a name containing
a space and a fake "teams=" token could shadow the real trailing team
field and silently misdirect a caller's inbox/send/history to an
attacker-controlled team. kv_get now keeps the last match, matching the
rightmost-wins behavior check-inbox.sh's own parser already relies on.
co1's PR #487 review caught that this doesn't close the finding: whoami.sh's
single-match line is "agent=<n> teams=<t> type=<ty> project=<p>", and
project (like agent name) is attacker-influenceable and sorts LAST. A
project path crafted to contain a trailing "teams=<x>" token defeats
last-match the same way the original bug defeated first-match — the
line's ambiguity isn't resolvable by picking a match order, since both
ends can carry attacker content. A real fix needs whoami.sh to emit a
delimiter-safe format and every consumer (check-inbox.sh, identities.sh,
rename-team.sh, reset.sh, dispatch.sh) to be updated to match — an
interface change, not a contained parsing fix. Reverting to keep this PR
scoped to the F14 fix, which stands on its own.
@fujibee fujibee changed the title fix: close hook-command and identity-resolution hardening gaps (F14/F19) fix: shell-quote delivery hook command paths (F14) Jul 24, 2026
@fujibee
fujibee merged commit f01ce75 into main Jul 24, 2026
12 of 13 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

Development

Successfully merging this pull request may close these issues.

1 participant