Where: packages/safe-bash/src/shell/runtime.ts:3323-3345 — command lookup walks every PATH component with a stat (+ access on hit) per lookup, with no result caching and no per-exec FS-op budget. PATH is bounded only by maxExpansionBytes (16 MB) / maxExpansionFields (10 000), so ~9 000–10 000 components are admissible.
PoC (instrumented MemoryFileSystem counting stat/access/lstat/readFile/readdir):
PATH="$(printf '/n:%.0s' $(seq 1 9000))" # 9 000 nonexistent dirs, ~36 KB
mycmd # => 9 000 FS ops, 364 ms on memory FS
mycmd; mycmd # each lookup re-walks: 3 commands => 27 000 FS ops
On the in-memory FS this is just CPU (~0.4 ms/1 000 entries). On an S3- or WebDAV-backed deployment each stat is an HTTP round-trip: one failed command lookup = 9 000 billed subrequests; a 100-command script = ~900 000. There is no negative-result cache, no per-exec FS-operation ledger, and the walk is not charged to any budget (only throwIfAborted between entries).
Impact: (d) — subrequest-budget exhaustion and direct billing amplification on remote-FS deployments (Workers plan limits 50/1 000/5 000 subrequests are blown by a single command-not-found); on Node it's a minor CPU burn. Compounds v1 #6 / H6 (redirect I/O amplification) — same missing "FS operations are a budgeted resource" ledger, on the hottest path in the shell (every external command dispatch).
Fix: (1) cache PATH lookup results per-exec (positive and negative) keyed by (PATH value, name); (2) cap PATH components consulted per lookup (e.g. 64 — legitimate PATHs are short); (3) charge FS ops to a per-exec maxFsOps ledger shared with the redirect/glob paths. (1)+(2) together make the worst case 64 ops per distinct command name.
Where:
packages/safe-bash/src/shell/runtime.ts:3323-3345— command lookup walks every PATH component with astat(+accesson hit) per lookup, with no result caching and no per-exec FS-op budget. PATH is bounded only bymaxExpansionBytes(16 MB) /maxExpansionFields(10 000), so ~9 000–10 000 components are admissible.PoC (instrumented MemoryFileSystem counting stat/access/lstat/readFile/readdir):
On the in-memory FS this is just CPU (~0.4 ms/1 000 entries). On an S3- or WebDAV-backed deployment each
statis an HTTP round-trip: one failed command lookup = 9 000 billed subrequests; a 100-command script = ~900 000. There is no negative-result cache, no per-exec FS-operation ledger, and the walk is not charged to any budget (onlythrowIfAbortedbetween entries).Impact: (d) — subrequest-budget exhaustion and direct billing amplification on remote-FS deployments (Workers plan limits 50/1 000/5 000 subrequests are blown by a single command-not-found); on Node it's a minor CPU burn. Compounds v1 #6 / H6 (redirect I/O amplification) — same missing "FS operations are a budgeted resource" ledger, on the hottest path in the shell (every external command dispatch).
Fix: (1) cache PATH lookup results per-exec (positive and negative) keyed by (PATH value, name); (2) cap PATH components consulted per lookup (e.g. 64 — legitimate PATHs are short); (3) charge FS ops to a per-exec
maxFsOpsledger shared with the redirect/glob paths. (1)+(2) together make the worst case 64 ops per distinct command name.