Skip to content

safe-bash tee: uncapped operand count — ~6k targets × 1-byte payload = fatal OOM at 128 MB isolate #631

Description

@kamilio

Where: packages/safe-bash/src/commands/streams.ts:325-360tee opens every operand up front (targets.add(await openFileOutput(...)) in the operand loop) with no operand-count cap and no file-descriptor budget. Each open target retains stream/sink state (~14 KB heap per target measured) for the lifetime of the command. Only the per-command argv cap (64 KB) and maxExpansionFields (10 000) indirectly bound the count — and 64 KB of argv buys ~6 000–9 000 targets (/d/fNNNN).

PoC (Node 22, --max-old-space-size=128 as Workers-isolate proxy):

seq 1 9000 | xargs printf "/d/f%s\n" > /list; mkdir /d
printf "x" > /payload
tee $(cat /list) < /payload > /sink     # 1-byte payload!

fatal V8 OOM at 128 MB heap (uncatchable). Calibration: 4 000 targets → exit 0, +49 MB heap; 6 000 → OOM. Note the output-byte budget never engages: the payload is 1 byte per file (9 KB total); the memory cost is purely per-open-target structural overhead. At default Node heap, 9 000 targets × 128 KiB payload = +252 MB transient.

Impact: (d) — a ~110-byte script kills a Workers isolate (taking co-resident tenants' in-flight work with it) with all byte budgets green; also an FD-exhaustion vector on real-fs backends. Same uncovered class as v2 H4 (pipeline stages) but on the tee write path; v1 #11 noted "uncapped tee operand count (2 000 targets, 25 ms)" without the memory-amplification measurement.

Fix: cap tee operands (e.g. maxTeeTargets ≈ 64) like the v2 maxPipelineStages fix; alternatively stream targets in bounded batches (open → write → close per window) and charge each open target to a descriptor/arena ledger.

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