Skip to content

mcpx(settings): byte sizes accept negatives and int64 overflow — http.streamBufferInit=-1 passes validation, then panics the CLI with 'makeslice: cap out of range' at the first streaming read #1697

Closed

Description

@dezren39

Summary

Byte-size settings (KindBytes) accept negative and overflowing values: settings.ParseBytes returns them with no error, Validate/Normalize pass them through, and at least one consumer spends the value as a slice capacity with no guard — so a config file, env var, or runtime override that sets http.streamBufferInit to -1 (or to a size so large it overflows int64) crashes the CLI with makeslice: cap out of range the first time it reads a streaming response.

Evidence (verified this run)

Line trace, pkgs/mcpx/internal/settings/value.go:

  • ParseBytes (:450-479) strips a suffix and does strconv.ParseFloat + int64(f * float64(mult)) with no sign or range check. A negative literal parses cleanly; a huge one converts out-of-range float → int64 (on amd64/arm64: math.MinInt64).
  • Validate (:481+, KindBytes case at :503) only checks that ParseBytes returned no error — so every value above is a valid setting. Apply and SetRuntime both gate on Normalize → Validate, so the bad value is admitted at every layer (file, env, flag, preset, runtime API).
  • Unguarded consumer: internal/cli/client.go:965-966 and internal/cli/opcmd.go:556-557 both do sc.Buffer(make([]byte, 0, c.set.Bytes("http.streamBufferInit")), int(c.set.Bytes("http.streamBufferMax"))) — a negative init value is a negative make cap, which panics.
  • Other consumers happen to be guarded, which is why this stayed hidden: artifacts treats MaxBytes > 0 / Quota <= 0 as "no ceiling" (internal/artifacts/artifacts.go:191,354-355) and logging substitutes the default when maxBytes <= 0 (internal/logging/file.go:86-88). Those guards silently reinterpret a negative a user actually set — worth a triage look, but the crash is the headline. http.bodyLimit / http.callBodyLimit feed http.MaxBytesReader in internal/daemon/routes_secrets.go:49,114 and server.go:870 with whatever Bytes() returns.
  • The one existing ParseBytes test (internal/settings/registry_test.go, TestByteSizesAcceptBothDecimalAndBinarySuffixes) covers only well-formed positive sizes.

Laptop probe (real internal/settings package, detached worktree at origin/main 211aa58; value.go sha256 c669f256, identical to the sandbox clone; probe + log in the goal's hidden_files/probe-2026-10-28-laneA-bytes/):

ParseBytes(-1) = -1, err=<nil>
ParseBytes(-5MB) = -5000000, err=<nil>
ParseBytes(999999999999999999999999TB) = -9223372036854775808, err=<nil>
Validate accepted byte size "-1" / "-5MB" / "999999999999999999999999TB"   (KindBytes, http.streamBufferInit decl)
Normalize accepted the same three
make([]byte, 0, ParseBytes(-1)) panicked: runtime error: makeslice: cap out of range

Baseline: with the probe removed, the full existing internal/settings suite passes on the same tree.

Why it matters

The settings system is the one choke point whose whole job is keeping an invalid value out of a running process ("a runtime change that skips the parser is the one way to get an invalid value into a running process" — value.go, SetRuntime). A size is the easiest typo to make (-1 is a common "unlimited" idiom in other tools), and here it either crashes the client at first stream or — at the guarded consumers — silently turns a set limit into "no limit / default", the opposite of what was configured. Overflow needs no malice either: 999999999999999999999999TB is what a fat-fingered or generated config produces, and it lands as the most negative int64 there is.

Acceptance criteria

  • ParseBytes (or Validate for KindBytes) refuses negative results and magnitudes that do not fit in an int64, with an error that names the offending value — ParseBytes("-1"), ParseBytes("-5MB") and the overflow case above all error.
  • A KindBytes setting therefore cannot be applied at any layer (file/env/flag/preset/runtime) with such a value; the error surfaces at apply time, not at first use.
  • Regression tests cover negative (bare and suffixed), overflow, and the existing well-formed cases (the current suffix table test keeps passing).
  • Triage confirms no consumer still spends a Bytes() value unguarded in a way a valid value can crash (e.g. an init buffer larger than the max, at the two scanner sites) — or files that separately.
  • Existing internal/settings, internal/cli and internal/daemon tests keep passing.

Notes for triage

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane A, new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a, run 2026-10-28 09:35 CDT
    • Found via: filed this run
    • Task: Triage the KindBytes validation gap: negative and int64-overflowing byte sizes are accepted at every settings layer, and http.streamBufferInit spent as a make() cap panics the CLI.
    • Expectation: effort/s — done when ParseBytes/Validate refuse negative and overflowing sizes at apply time, with regression tests.
    • Links: evidence and probe in the issue body; probe + log in the goal's hidden_files/probe-2026-10-28-laneA-bytes/
  4. added
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 31, 2026
  5. 16 remaining items

  6. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    and removed
    work/assignedQueue worker lifecycle state
    on Nov 1, 2026
  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Agent note — triage done (task 5164, lane E)

  8. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 2, 2026
  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Agent note — picked up (task 4257, lane E)

  10. added a commit that references this issue on Nov 2, 2026
  11. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Agent note — done (task 4257, lane E)

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

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions