Skip to content

Bound JSON reads from peers and fail closed when a peer's pin is gone - #27

Merged
JaredP94 merged 3 commits into
mainfrom
fix/request-bounds
Nov 2, 2026
Merged

JaredP94 merged 3 commits into
mainfrom
fix/request-bounds

Conversation

@JaredP94

@JaredP94 JaredP94 commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Description

Two hardening changes:

  1. Bounded JSON reads. HTTP timeouts bounded how long, not how much. Node-info answers are capped at 1 MiB and model inventories at 16 MiB (scanner, manual nodes, including this fork's oMLX and engine-manager probes); error-store ingest at 1 MiB (400 past it); remote engine progress at 1 MiB per NDJSON frame, so long operations still stream. Past a cap, the existing failure path is taken.
  2. Fail closed on a vanished pin. A peer candidate is resolved only while its pin is held, but the pin can go before the dial; the three proxies then fell back to an unpinned transport. They now refuse the dial with errPeerUnpinned.

Adapted from NVIDIA#167 and the fail-closed part of NVIDIA#79. That PR's 32 MiB request-body cap is not ported: upstream's maintainers rejected rejecting large bodies in favour of a disk-spooling design that hasn't landed.

Scope

nvpair-node-scanner, nvpair-manual-nodes, nvpair-errors, nvpair-engine-manager/remoteclient.go, the three proxies.

Validation

go test ./... in all seven modules, with new tests for each limit and for the unpinned dial.

Risk

Low; real answers are far below the limits. Bumps: scanner 1.2.1, manual-nodes 1.2.2, errors 1.1.1, engine-manager 1.4.0, ollama/lmstudio-proxy 1.4.1, omlx-proxy 1.4.2.

Checklist

  • I have read the Contributing Guidelines.
  • Every commit is signed off (git commit -s), certifying the Developer Certificate of Origin.
  • New or existing tests cover the change.
  • Relevant documentation is updated.
  • I checked the diff, changed filenames, and commit messages for credentials, private data, internal URLs, internal issue identifiers, and generated artifacts.
  • I recorded the validation commands and results above.
  • I bumped any affected component in services/versions.json, and described user-visible changes above so they reach the release notes.

Part of the upstream issue/PR review. Each branch is independent off main; they all bump services/versions.json, so the second one merged will need a trivial conflict resolution there.

JaredP94 and others added 3 commits November 2, 2026 20:42
HTTP timeouts bounded how long a read could take, not how much JSON it
could buffer. A peer or manual node could make the scanner, manual-nodes,
the error store or the engine manager parse an arbitrarily large answer.

- node-info answers: 1 MiB (scanner, manual nodes)
- model inventories: 16 MiB (scanner, manual nodes)
- the oMLX proxy's loopback-only 403 body: 64 KiB (manual nodes)
- error-store ingest: 1 MiB, refused with 400
- remote engine progress streams: 1 MiB per NDJSON frame, so a long
  operation still reports progress for as long as it runs

A value past its limit follows the existing failure path.

Adapted from NVIDIA#167, extended to this fork's
manual-node probes (oMLX, engine-manager models).

Co-authored-by: Kaylee Lubick <kjlubick@users.noreply.github.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
A peer candidate is resolved only while this node holds its certificate
pin, but the pin can be removed between resolution and dial. The proxies
then fell back to a transport with no pinned TLS configuration, relying
on the system roots to reject the peer's self-signed certificate.

Return a transport whose every dial fails with errPeerUnpinned instead,
so a vanished pin is an explicit refusal in all three proxies.

From NVIDIA#79. That PR's 32 MiB request-body cap is
not ported: upstream's maintainers rejected rejecting large bodies in
favour of a disk-spooling design that has not landed, and the plaintext
ingress is loopback-only.

Co-authored-by: Mallikh Kalkere <mkalkere@users.noreply.github.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
@JaredP94
JaredP94 merged commit 1367cee into main Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant