Skip to content

Close wrapper, deferred-command and stack-overflow bypasses in deniedBy - #1

Merged
devmaxxx merged 3 commits into
mainfrom
fix/close-wrapper-script-and-overflow-bypasses
Oct 17, 2026
Merged

devmaxxx merged 3 commits into
mainfrom
fix/close-wrapper-script-and-overflow-bypasses

Conversation

@devmaxxx

Copy link
Copy Markdown
Owner

Summary

An audit of deniedBy found about 65 command lines that run a denied command while the guard returned null, and one input that made it throw instead of returning a verdict.

  • Stack overflow fails closed. A deeply nested line ('$('.repeat(20000)) threw a RangeError. A PreToolUse hook that treats an error as "no decision" would have let the command run. The line is now reported as unreadable ('unbalanced quoting').
  • More wrappers come off. chrt, taskset, caffeinate, arch, strace, ltrace, nsenter, chroot, pkexec, run0, runuser, su -c, systemd-run, script, parallel, fd -x, ssh host …, yarn exec, bun x/bun exec, gtimeout, fakeroot, unshare, sandbox-exec, coproc and function bodies. The zsh-only forms =cmd, noglob, nocorrect, - and [[ … ]] cmd are read in strict mode only.
  • Commands set up to run later are read. trap actions, alias values, git rebase -x, git difftool -x, git bisect run, git submodule foreach, git filter-branch filters, and git -c values such as a pager, editor or ssh command. git config alias.* is denied.
  • Words xargs and parallel add count as expansions. This covers echo push | xargs git and xargs -I{} sh -c {}, including a replace-string inside an option cluster.
  • source of stdin or a process substitution is denied. source of a regular file is still allowed, as ./script is, so that source .venv/bin/activate keeps working.
  • Interpreter inline code is searched. The inline program of python -c, node -e, perl -e, ruby -e, php -r, osascript -e, awk and similar is searched for a pattern's words. This is a heuristic and the README says so.
  • rm operands are folded. //, /./, a trailing / or /., and .. are folded before matching.
  • Option parsing is fixed. Values attached to their option (-c'code') are read, ssh options after the host are skipped, and GNU time -f/-o and env -a/-P take their value.
  • DEFAULT_DENY grows. It adds pkexec, run0 and rm -rf ~/*.
  • Code is reorganized. The option tables move to src/wrappers.ts.

The README now compares against agent hooks (git-guardrails, dcg). It also documents the new limits.

Known gaps

  • Launchers not in the table still return null: setpriv, xcrun, direnv exec, op run, mise exec.
  • rm -rf ~/.. is denied as ~. That is stricter than needed, because resolving above ~ would need the real home path.

Test plan

  • pnpm test: 477 pass. Each closed bypass has a regression test, and the allowed everyday commands have tests too.
  • pnpm typecheck, pnpm lint and pnpm build pass, and publint is clean.
  • No false positives against DEFAULT_DENY for these common commands: source .venv/bin/activate, xargs wc -l, python -c "print(1)", ssh host uptime, git rebase -i, trap "rm -f $tmp" EXIT, alias ll='ls -la'.

An audit found lines that ran a denied command while deniedBy returned
null, and a deeply nested line that threw a RangeError, which a hook
that fails open on errors would let through.

- Catch stack overflow while reading and report the line as unreadable.
- Move wrapper option tables to wrappers.ts and add chrt, taskset,
  caffeinate, arch, unbuffer, strace, ltrace, nsenter, chroot, pkexec,
  run0, runuser, su -c, systemd-run, firejail, faketime, dbus-launch,
  xvfb-run, toybox, script, parallel, fd -x, ssh, yarn exec, bun x/exec,
  coproc, function, and zsh's =cmd, noglob, nocorrect, - and [[ ]] cmd.
- Read commands set up to run later: trap actions, alias values,
  git rebase -x, difftool -x, bisect run, submodule foreach,
  filter-branch filters and git -c values; deny git config alias.*.
- Treat the words xargs and parallel add, and xargs' replace-string,
  as expansions.
- Deny source of stdin or a process substitution.
- Search interpreter inline programs (python -c, node -e, perl -e,
  awk, ...) for a pattern's words.
- Fold //, /./ and trailing / or /. in rm operands.
- Add pkexec, run0 and rm -rf ~/* to DEFAULT_DENY.
Attached short-option values (-c'code', -x'cmd'), flock -c before the
lock file, ssh options after the host, GNU time -f/-o, env -a/-P,
clustered xargs -I, missing value options for parallel, npx and
systemd-run, `..` in rm operands, versioned interpreter names, eval --,
and gtimeout, fakeroot, unshare, sandbox-exec and similar launchers.
@devmaxxx devmaxxx mentioned this pull request Oct 17, 2026
3 of 5 tasks
@devmaxxx
devmaxxx merged commit e36b5c2 into main Oct 17, 2026
5 checks passed
@devmaxxx
devmaxxx deleted the fix/close-wrapper-script-and-overflow-bypasses branch October 17, 2026 17:27
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