Skip to content

fix(mcp,tools): correct fetchFn fallback order and Drive size-check hardening#5423

Merged
waleedlatif1 merged 1 commit into
stagingfrom
fix/mcp-ssrf-drive-size
Jul 4, 2026
Merged

fix(mcp,tools): correct fetchFn fallback order and Drive size-check hardening#5423
waleedlatif1 merged 1 commit into
stagingfrom
fix/mcp-ssrf-drive-size

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • mcpAuthGuarded: fix spread order so the SSRF-guarded fetch is only overridden by a genuine caller-supplied fetchFn, not silently disabled when options merely contains the key (e.g. fetchFn: undefined)
  • Google Drive download route: guard the early pre-download size check against a malformed/non-numeric metadata.size string so it's skipped explicitly rather than relying on an incidental NaN no-op; the streaming cap on the actual download still enforces the limit either way

Type of Change

  • Bug fix

Testing

  • Added a test confirming mcpAuthGuarded falls back to the guarded fetch when fetchFn: undefined is passed explicitly (in addition to existing default/override coverage)
  • Added a test confirming a malformed metadata.size doesn't crash and the download proceeds to the (separately tested) streaming cap
  • bun vitest run on both touched test files, tsc --noEmit, biome check, and bun run check:api-validation all pass

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Spread order previously let an explicit fetchFn (including fetchFn: undefined)
in options silently disable the SSRF-guarded default. Fallback is now applied
after the spread so the guard always wins unless a real override is passed.

fix(tools): handle non-numeric Drive file size in early size check

Guard the pre-download size check against a malformed metadata.size string
so it's skipped explicitly instead of relying on an incidental NaN no-op;
the streaming cap on the actual download still enforces the limit either way.
@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 4, 2026 11:37pm

Request Review

@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches MCP OAuth fetch wiring (SSRF-sensitive); changes are small and restore intended guard behavior rather than new surface area.

Overview
Fixes mcpAuthGuarded so the SSRF-guarded MCP fetch is applied when callers pass fetchFn: undefined (or omit a real override). Options are spread first, then fetchFn is set with ??, so an explicit undefined no longer wipes out the default guard.

For Google Drive downloads, the pre-download metadata size check now runs only when metadata.size parses to a finite number; malformed values skip the early check and the download continues with maxResponseBytes still enforcing the cap on the actual fetch.

Reviewed by Cursor Bugbot for commit 7d40bc9. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two distinct defensive bugs: the SSRF-guarded fetch in mcpAuthGuarded was silently disabled when a caller spread { fetchFn: undefined } into options, and the Google Drive download route relied on incidental NaN behavior to skip an oversized pre-flight check for malformed metadata.size strings.

  • auth.ts: Switches from { fetchFn: guard(), ...options } (spread wins, drops the guard on fetchFn: undefined) to { ...options, fetchFn: options.fetchFn ?? guard() } (nullish coalescing ensures the SSRF guard is always applied unless a real function is explicitly provided).
  • route.ts: Wraps parseInt(metadata.size, 10) in Number.isFinite() so a non-numeric size string explicitly skips the early check rather than relying on assertKnownSizeWithinLimit silently tolerating NaN; the maxResponseBytes streaming cap still enforces the hard limit on the actual download.

Confidence Score: 5/5

Both changes are minimal, correctly targeted, and backed by focused new tests — safe to merge.

The auth fix is a one-liner that eliminates a real gap (the SSRF guard being silently dropped when options spread an undefined fetchFn), and the ?? operator's short-circuit semantics are unambiguous. The Drive route change adds an explicit Number.isFinite guard that makes the skip-on-bad-input path intentional rather than incidental, while the streaming cap remains the hard enforcement boundary either way. Test coverage is tight and directly exercises the new behavior in both files.

No files require special attention; all four changed files are straightforward.

Important Files Changed

Filename Overview
apps/sim/lib/mcp/oauth/auth.ts Correct fix: nullish coalescing replaces spread-order dependence, ensuring the SSRF-guarded fetch is always applied when options.fetchFn is undefined or absent
apps/sim/lib/mcp/oauth/auth.test.ts New test for explicitly-undefined fetchFn correctly validates the fix; existing override test passes but is missing a complementary assertion
apps/sim/app/api/tools/google_drive/download/route.ts Size-check hardening is correct: Number.isFinite guard makes the NaN skip explicit and the streaming cap via maxResponseBytes remains the enforced limit
apps/sim/app/api/tools/google_drive/download/route.test.ts New malformed-size test verifies the skip and confirms the streaming cap option is still passed; well-structured addition to the existing test suite

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant mcpAuthGuarded
    participant createSsrfGuardedMcpFetch
    participant auth

    Note over Caller,auth: Before fix — fetchFn: undefined silently disabled the guard
    Caller->>mcpAuthGuarded: "options = { fetchFn: undefined }"
    mcpAuthGuarded->>createSsrfGuardedMcpFetch: createSsrfGuardedMcpFetch()
    createSsrfGuardedMcpFetch-->>mcpAuthGuarded: guardedFetch
    Note over mcpAuthGuarded: spread overwrites guardedFetch with undefined
    mcpAuthGuarded->>auth: fetchFn: undefined — SSRF guard lost

    Note over Caller,auth: After fix — nullish coalescing preserves the guard
    Caller->>mcpAuthGuarded: "options = { fetchFn: undefined }"
    Note over mcpAuthGuarded: options.fetchFn ?? createSsrfGuardedMcpFetch()
    mcpAuthGuarded->>createSsrfGuardedMcpFetch: createSsrfGuardedMcpFetch()
    createSsrfGuardedMcpFetch-->>mcpAuthGuarded: guardedFetch
    mcpAuthGuarded->>auth: fetchFn: guardedFetch — guard preserved

    Note over Caller,auth: Caller-supplied fetchFn still overrides
    Caller->>mcpAuthGuarded: "options = { fetchFn: overrideFetch }"
    Note over mcpAuthGuarded: overrideFetch is non-null, short-circuit skips guard creation
    mcpAuthGuarded->>auth: fetchFn: overrideFetch
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant mcpAuthGuarded
    participant createSsrfGuardedMcpFetch
    participant auth

    Note over Caller,auth: Before fix — fetchFn: undefined silently disabled the guard
    Caller->>mcpAuthGuarded: "options = { fetchFn: undefined }"
    mcpAuthGuarded->>createSsrfGuardedMcpFetch: createSsrfGuardedMcpFetch()
    createSsrfGuardedMcpFetch-->>mcpAuthGuarded: guardedFetch
    Note over mcpAuthGuarded: spread overwrites guardedFetch with undefined
    mcpAuthGuarded->>auth: fetchFn: undefined — SSRF guard lost

    Note over Caller,auth: After fix — nullish coalescing preserves the guard
    Caller->>mcpAuthGuarded: "options = { fetchFn: undefined }"
    Note over mcpAuthGuarded: options.fetchFn ?? createSsrfGuardedMcpFetch()
    mcpAuthGuarded->>createSsrfGuardedMcpFetch: createSsrfGuardedMcpFetch()
    createSsrfGuardedMcpFetch-->>mcpAuthGuarded: guardedFetch
    mcpAuthGuarded->>auth: fetchFn: guardedFetch — guard preserved

    Note over Caller,auth: Caller-supplied fetchFn still overrides
    Caller->>mcpAuthGuarded: "options = { fetchFn: overrideFetch }"
    Note over mcpAuthGuarded: overrideFetch is non-null, short-circuit skips guard creation
    mcpAuthGuarded->>auth: fetchFn: overrideFetch
Loading

Reviews (1): Last reviewed commit: "fix(mcp): correct fetchFn fallback order..." | Re-trigger Greptile

@waleedlatif1 waleedlatif1 merged commit 3edaae3 into staging Jul 4, 2026
18 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/mcp-ssrf-drive-size branch July 4, 2026 23:44
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