Skip to content

fix(host-agent): reject oversized JSON bodies - #2965

Open
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/host-agent-json-body-limit
Open

fix(host-agent): reject oversized JSON bodies#2965
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/host-agent-json-body-limit

Conversation

@tang-vu

@tang-vu tang-vu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • reject JSON request bodies larger than the host-agent MAX_BODY limit with HTTP 413
  • close the HTTP connection before any oversized payload bytes are consumed
  • read the declared length directly once it has passed the bound

Why this matters

Every host-agent JSON mutation endpoint calls read_json_body() or read_optional_json_body(). Both readers previously consumed min(Content-Length, MAX_BODY) and attempted to parse that prefix. A caller declaring an oversized body could therefore get inconsistent results (including acceptance when the available prefix happened to be valid JSON), while unread bytes remained on a persistent HTTP connection and could corrupt framing for the next request.

Root cause: MAX_BODY was used as a truncation length instead of an admission limit. The invariant is that a JSON request is either read exactly as declared within the configured bound, or rejected before consumption with the connection closed.

This is runtime correctness at the authenticated host-agent boundary; it is not presented as an unauthenticated remote security issue.

Overlap check

Searched open and closed PR titles for host-agent body, Content-Length host agent, MAX_BODY JSON, and request body too large. No semantic match exists. I also inspected every open PR touching ods/bin/ods-host-agent.py; current work there concerns OpenCode lifecycle, GPU/runtime planning, rootless reachability, PID writes, and remote-provider state transactions, not HTTP body framing.

Merged file history was also checked; the nearest body-size work is the endpoint-specific .env update cap, which does not protect the shared JSON readers.

Regression test

The parameterized boundary test calls both shared readers with Content-Length = MAX_BODY + 1 and a syntactically valid prefix. It asserts 413, Connection: close state, and that zero payload bytes were consumed.

Pre-fix evidence: both cases returned {}. Post-fix validation:

  • pytest tests/test_host_agent.py -q — 259 passed, 4 skipped
  • python -m py_compile ../../../bin/ods-host-agent.py tests/test_host_agent.py — passed
  • git diff --check — passed

Tradeoffs and rollback

Oversized requests now require a new connection after the 413 response; this is intentional because the body is not drained. Valid requests at or below MAX_BODY are unchanged. Revert commit 0fdb3dd1 to roll back; no state or schema migration is involved.

Generated with Codex

Batch compatibility

Validated as an independent ten-PR batch from upstream main 6ff9b4fc5190099705043acaab7e9b6ad9c8b8f1. The final PR heads merged without conflicts in this order: #2964 -> #2965 -> #2967 -> #2969 -> #2970 -> #2971 -> #2972 -> #2973 -> #2974 -> #2975. The resulting local synthetic merge head is 4ae60eadad9696a9accb735aad71af87d2be802d.

Combined validation on that exact tree:

  • Dashboard API boundary suites: 323 passed, 4 skipped.
  • Token Spy suite: 36 passed, 1 skipped.
  • Privacy Shield suite: 55 passed.
  • APE suite: 47 passed.
  • Python compile checks and git diff --check: passed.

The scopes are behaviorally independent. The stated order is the tested rollback/merge sequence for shared-file changes; each PR remains individually useful and revertible.

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