Skip to content

fix: max payload size in web fetch#883

Open
afjcjsbx wants to merge 2 commits intosipeed:mainfrom
afjcjsbx:fix/max-payload-size-in-web-fetch
Open

fix: max payload size in web fetch#883
afjcjsbx wants to merge 2 commits intosipeed:mainfrom
afjcjsbx:fix/max-payload-size-in-web-fetch

Conversation

@afjcjsbx
Copy link
Contributor

📝 Description

Implemented a strict memory limit on the WebFetchTool response body to prevent Out of Memory (OOM) crashes and bandwidth exhaustion when the agent attempts to fetch excessively large files (e.g., massive PDFs, ISOs, or infinite streams).

Changes made:

  • Replaced the vulnerable io.LimitReader + io.ReadAll combo with http.MaxBytesReader. This ensures that if the response exceeds the 10MB limit, the tool explicitly drops the TCP connection and returns an explicit *http.MaxBytesError, rather than silently returning a truncated response.
  • Added a robust unit test (TestWebFetchTool_PayloadTooLarge) to dynamically verify the OOM protection mechanism.

🗣️ Type of Change

  • 🐞 Bug fix (non-breaking change which fixes an issue / prevents OOM)
  • ✨ New feature (non-breaking change which adds functionality)
  • 📖 Documentation update
  • ⚡ Code refactoring (no functional changes, no api changes)

🤖 AI Code Generation

  • 🤖 Fully AI-generated (100% AI, 0% Human)
  • 🛠️ Mostly AI-generated (AI draft, Human verified/modified)
  • 👨‍💻 Mostly Human-written (Human lead, AI assisted or none)

🔗 Related Issue

N/A

📚 Technical Context (Skip for Docs)

  • Reference URL:
  • Reasoning: Fetching arbitrary URLs provided by an LLM exposes the service to OOM risks. io.LimitReader only stops reading but allows the connection to remain open, masking the limit as a normal EOF. http.MaxBytesReader is the idiomatic way to cap memory consumption in Go; it actively aborts the connection upon reaching the threshold, protecting the host's RAM and network resources.

🧪 Test Environment

  • Hardware: PC / Mac
  • OS: macOS / Linux
  • Model/Provider: All
  • Channels: All

📸 Evidence (Optional)

Click to view Logs/Screenshots
=== RUN   TestWebFetchTool_PayloadTooLarge
--- PASS: TestWebFetchTool_PayloadTooLarge (0.01s)
PASS

Copy link

@nikolasdehor nikolasdehor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-implemented fix. Using http.MaxBytesReader is the correct idiomatic approach in Go — it actively tears down the connection rather than silently truncating. The test is thorough and the PR description is excellent. One minor note: MaxFetchLimitBytes is exported. If no external packages need it, consider making it unexported (maxFetchLimitBytes). The test is in the same package so it would still have access. LGTM — good work preventing OOM from unbounded fetches.

Copy link

@nikolasdehor nikolasdehor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good hardening. The key improvement is replacing io.LimitReader (which silently truncates and returns io.EOF) with http.MaxBytesReader (which returns a typed *http.MaxBytesError and actively closes the connection). This gives the tool a clear signal that the content was too large, and allows returning an explicit error message to the LLM.

The error handling correctly uses errors.As to check for *http.MaxBytesError, and the test generates a payload slightly over the limit to verify the error path.

One nit (non-blocking): MaxFetchLimitBytes is exported but only used within the tools package. Consider making it unexported (maxFetchLimitBytes) unless external consumers need to reference it. The test is in the same package so it can access unexported symbols.

LGTM.

pkg/tools/web.go Outdated
const (
userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
MaxFetchLimitBytes = int64(10 * 1024 * 1024) // 10MB limit
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in configuration with default 10MB limit

@afjcjsbx
Copy link
Contributor Author

@mengzhuo make sense!

fixed

@afjcjsbx afjcjsbx requested a review from mengzhuo February 28, 2026 12:36
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.

3 participants