Repository navigation
Cap A2A unary HTTP bodies against unbounded remotes - #326
Merged
Merged
Conversation
rpc_call and http_get appended every write-callback byte with no size limit. SSE was capped in #317, but a hostile agent-card or JSON-RPC peer that omits Content-Length could still grow the process until OOM. Refuse bodies over 16 MiB (inbound API / kSseMaxEventBytes), abort via MAXFILESIZE and the write callback, and clear a partial buffer. Co-authored-by: Tyler Reckart <tylerreckart@users.noreply.github.com>
macos-arm64 CI raced the 80 ms pause plus helper thread: resolve finished after the planter, so O_NOFOLLOW never saw the swap. Plant the leaf symlink from a post-resolve hook instead. Co-authored-by: Tyler Reckart <tylerreckart@users.noreply.github.com>
…dy-cap # Conflicts: # CHANGELOG.md # tests/test_sandbox_ssrf.cpp
tylerreckart
enabled auto-merge (squash)
September 21, 2026 13:24
Keep both Unreleased changelog entries. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_87e4c98d-c61b-4c5b-b531-36c16eb94eba) |
Keep both Unreleased changelog entries. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f57a64bf-3aa0-41e7-81b4-81e1247cf182) |
Keep both Unreleased changelog entries. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep both Unreleased changelog entries. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
#317cappedSseReaderline/event buffers so a remote A2A or--connectstream cannot OOM the process.rpc_callandhttp_getstill appended every libcurl write-callback byte with no size limit. A hostile agent-card or JSON-RPC peer that omitsContent-Length(or advertises a huge one) can growHttpResponse::bodyuntil OOM. Timeouts bound duration, not memory — a fast peer can still push gigabytes.--connectand A2A federation share this client. The inbound HTTP API already rejects bodies over 16 MiB; the unary outbound path did not.Fix
Cap unary responses at 16 MiB (
kHttpMaxBodyBytes, same askSseMaxEventBytesand the inbound API).CURLOPT_MAXFILESIZE_LARGErefuses a declared oversizeContent-Lengthbefore download; the write callback aborts if a streamed body crosses the cap. Partial buffers are cleared and the error isresponse exceeded size limit.rpc_streamis unchanged: it already caps diagnostic raw bytes at 1 MiB and events viaSseReader.Tests
New
unit_a2a_httploopback suite (ssrf_guardoff):Content-Lengthover the cap is refusedContent-Lengthis refused at the write callback; body is emptyIndependently mergeable against
main. Touchessrc/a2a/http.cpp,include/a2a/http.h,tests/test_a2a_http.cpp,CMakeLists.txt, andCHANGELOG.md[Unreleased]. No overlap with #321–#325 except the Unreleased changelog heading (same as those PRs with each other).Note
Medium Risk
Caps affect all federation/agent-card and JSON-RPC unary fetches through
a2a/http.cpp; hostile peers are bounded, but legitimate responses over 16 MiB will fail. Unresolved merge conflicts in the sandbox SSRF test (and CMake) would break the build until fixed.Overview
Outbound A2A unary HTTP (
rpc_call,http_get) now enforces a 16 MiB ceiling viakHttpMaxBodyBytes, aligned with inbound API limits andkSseMaxEventBytes. libcurl getsCURLOPT_MAXFILESIZE_LARGE, and the write callback stops appending once the cap is hit, clears partial bodies, and surfacesresponse exceeded size limitinstead of buffering unbounded streams whenContent-Lengthis missing or wrong.rpc_streamis unchanged (already capped bySseReader).A separate
unit_a2a_httploopback test binary covers small GET success, oversizeContent-Length, and chunked overflow withoutContent-Length.Sandbox
/readTOCTOU coverage adds a test-onlyread_check_hookonSandboxConfig(runs after resolve, beforeO_NOFOLLOWopen) so the leaf-symlink-swap case can plant the swap deterministically instead of racing a pause + helper thread on macOS CI.Note: The diff still contains unresolved merge conflict markers in
tests/test_sandbox_ssrf.cpp(and a conflicting CMake block vsunit_remote_http/unit_json_numbers); those must be resolved before merge.Reviewed by Cursor Bugbot for commit 0a1a1b5. Bugbot is set up for automated code reviews on this repo. Configure here.