Skip to content

gstack-redact: invalid --max-bytes silently turns the fail-closed oversize guard into fail-open #1824

Closed

Description

@jbetala7

Observed problem

gstack-redact's oversize check is documented and designed to fail closed (lib/redact-engine.ts: "Fail CLOSED on oversize input"). A malformed --max-bytes value silently turns it into fail open — the guard is skipped and oversized input is scanned (or, with a negative value, every input is blocked).

Root cause is a two-step gap:

  1. bin/gstack-redact parses the flag with parseInt(maxBytes, 10) and passes the result straight through:

    const maxBytes = arg("--max-bytes");
    return {
      ...
      ...(maxBytes ? { maxBytes: parseInt(maxBytes, 10) } : {}),
    };

    parseInt("foo", 10) → NaN, which is passed to the engine as maxBytes: NaN.

  2. The engine only guards against null/undefined:

    const maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
    ...
    if (byteLen > maxBytes) { /* fail-closed block */ }

    ?? does not catch NaN, so maxBytes stays NaN, and byteLen > NaN is always false. The fail-closed block never fires.

Current behavior on upstream main

  • gstack-redact --max-bytes notanumber < huge_input — the oversize fail-closed guard is skipped entirely (input that should be blocked at the cap is scanned anyway). The user believes they set a cap; they silently got no cap.
  • gstack-redact --max-bytes -5 < anything — byteLen > -5 is always true, so every input is blocked as "too large", with a nonsensical > -5 bytes message.
  • Calling scan(input, { maxBytes: NaN }) directly returns oversize: false for arbitrarily large input.

Expected behavior

An invalid size cap must never weaken the fail-closed guard:

  • The engine should treat a non-finite or non-positive maxBytes as invalid and fall back to the known-good DEFAULT_MAX_BYTES (1 MiB), so the guard stays intact for every caller.
  • The CLI should reject a malformed --max-bytes with a clear error and a usage exit code (1), instead of silently passing NaN.

Duplicate searches performed

Candidate fix shape

  • lib/redact-engine.ts: replace opts.maxBytes ?? DEFAULT_MAX_BYTES with a validity check (Number.isFinite && > 0, else DEFAULT_MAX_BYTES).
  • bin/gstack-redact: validate --max-bytes is a positive integer; otherwise write an error to stderr and process.exit(1).
  • Regression tests in test/redact-engine.test.ts (invalid maxBytes still fails closed) and test/gstack-redact-cli.test.ts (malformed --max-bytes exits 1).

Activity

  1. jbetala7 commented on Jun 1, 2026

    @jbetala7
    ContributorAuthor

    Opened #1825 with the fix (engine fail-safe fallback + CLI validation) and regression tests at both layers.

  2. Sushanth012 commented on Jun 5, 2026

    @Sushanth012

    I'll contribute to this

  3. garrytan commented on Jun 8, 2026

    @garrytan
    Owner

    Fixed in #1911 (v1.57.6.0). The CLI now rejects a non-integer/non-positive --max-bytes before scanning, and the engine falls back to the default cap for any non-finite value, so the fail-closed oversize guard can't be silently disabled. Thanks @jbetala7. Auto-closes on merge.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions