Relationships
#2336 exec: sudo=true only escalates the first ; separated command, later commands run unprivileged and fail silently
Opened by josephholsten · 9/22/2026· Shipped 9/25/2026
When exec is called with sudo: true, applySudo (models/_lib/runner.ts:151) does a plain string prefix:
sudo ? `sudo -n -- ${command}` : commandFor a single command this works. But when command is a ;-chained shell string (e.g. systemctl status foo; cat /var/run/foo.pid), the result is:
sudo -n -- systemctl status foo; cat /var/run/foo.pidsudo -n -- only wraps the first statement up to the first ;. Everything after the semicolon is a separate shell statement outside the sudo invocation and runs as the unprivileged SSH user. The two operations in operations.ts:391 (runExec) and the analogous script path both hit this, since applySudo is a naive string concat with no awareness of shell control operators (;, &&, ||, |, newlines).
Reproduction
Fleet host requires sudo to read a root-owned file. Run:
swamp model method run <fleet> exec \
--input hosts=<host> \
--input sudo:json=true \
--input command='systemctl status foo.service; cat /var/run/foo.pid'Expected
Both commands run under sudo, or the method refuses/errors on a ;-chained command with sudo: true rather than silently mis-escalating.
Actual
Only systemctl status foo.service runs as root. cat /var/run/foo.pid runs unprivileged, hits Permission denied against the root-owned pidfile, and the caller has no way to distinguish "command legitimately failed" from "command ran without the privilege it was supposed to have." In a diagnostic script this silently misreports state (e.g. a running root-owned service gets reported as "not running" because the pidfile read failed on permissions, not absence).
Suggested fix approach
Either (a) wrap the whole command in a nested shell so sudo escalates the full pipeline — sudo -n -- sh -c '<command>' — with correct quoting of the inner string, or (b) detect shell control operators in command when sudo: true and reject with a clear error telling the caller to use script (which pipes over stdin to a single interpreter invocation) instead of chaining in exec.
Discovered while diagnosing a Lilwoods Infrastructure fleet service-status check (LIM-153) where a root-owned pidfile read after a sudo-gated systemctl call was silently reported as "service not running" due to this escalation gap.
Upstream repository: https://github.com/swamp-club/swamp-extensions
Environment
- Extension:
@swamp/ssh@2026.07.02.1 - swamp:
20260902.182442.0-sha.d4bc7fac - OS:
darwin(aarch64) - Deno:
2.9.6 - Shell:
/bin/zsh
Shipped
Click a lifecycle step above to view its details.
stack72 commented 9/25/2026, 10:15:20 PM
Thanks @josephholsten for reporting this! We shipped: Make exec sudo=true escalate the entire command line. applySudo keeps the exact sudo -n -- prefix for plain word-list commands (sudoers-compatible, already fully escalated) and wraps anything containing shell syntax as sudo -n -- sh -c with a POSIX single-quoted command, so every statement, redirect, expansion and builtin runs as root. script output is unchanged. Adds unit, execution-level (fake sudo, across sh/bash/zsh) and model-level tests, a version bump with upgrade note, and README/manifest doc updates.. The fix has been merged and a release is on its way. We appreciate your contribution to swamp.
Sign in to post a ripple.