Skip to content

safe-bash getopts: re-validates every positional argument on every call — O(n²) parse loop, 2 000 options = full 30 s CPU budget #667

Description

@kamilio

Where: packages/safe-bash/src/shell/runtime.ts ~:3583-3601 (per-call admit() loop over all args + scanGetopts) and src/shell/getopts.ts scanGetopts (validateString over every positional argument on every call, each char a work.step() with yieldTurn every 128). Per-call cost ∝ total argv bytes, so a while getopts loop over n options is O(n²). A single long clustered word (-abc…) is also O(len²).

PoC (~120 bytes, default limits):

set -- $(for i in $(seq 1 1000); do printf -- "-a "; done); while getopts "a" o; do :; done; echo $OPTIND
x=$(printf -- "-abcdefghij%.0s" {1..300}); set -- $x; while getopts "abcdefghij" o; do :; done

Measured: 250 opts → 1 958 ms; 500 → 4 506 ms (re-verified independently: 8 843 ms vs 1 696 ms for a plain 500-iteration while loop); 1000 → 13 435 ms (control: plain 1000-iteration loop 2 062 ms); 2000 → maxCpuMs at 30 007 ms. Clustered 3.3 KB word → 28 397 ms.

Impact: (d) — ~120-byte script consumes the whole per-exec CPU budget; interruptible, so bounded by the wall clock.

Fix: validate/charge arguments once per set/positional change (cache by identity) and have scanGetopts scan only the current token.

Found in security audit v3 (2026-09-07).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions