Skip to content

safe-bash: PATH command lookup walks every component with uncached stat+access — 9k-entry PATH = 9k FS ops per command, no budget #648

Description

@kamilio

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.

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

    Labels

    bugSomething is not working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions