MCP06
- Location
dist/.setup/parallel-search-normalize-BDJxllHh.mjs:45- Finding
Unwrapped Upstream Metadata Enables Indirect Prompt Injection in Search Results ## Remediation Suggestions 1. **Validate metadata against explicit schemas.** Restrict `usage` to documented fields with expected numeric types and sensible bounds. Reject unexpected strings, nested objects, and unknown fields. 2. **Remove unnecessary upstream text.** Omit `warnings` if it is not required for the agent’s task. Otherwise, accept only bounded strings and process each through `wrapWebContent`. 3. **Protect every upstream-controlled text field consistently.** Review identifiers, URLs, publication metadata, and remote error text rather than assuming the result-level `wrapped` flag covers all content. 4. **Retain accurate trust metadata.** Do not declare a payload fully wrapped while forwarding unwrapped upstream text. Continue marking provider-derived content as untrusted. 5. **Cache only validated, normalized results.** Invalidate existing cache entries when deploying the revised schema. 6. **Add regression tests for both providers.** Verify that instruction-bearing warning strings, nested usage objects, oversized arrays, and unexpected metadata are rejected, omitted, or wrapped before reaching the model.
- Content
View full analysis
Vulnerability Details
File Location:
dist/.setup/parallel-search-normalize-BDJxllHh.mjs, lines 45–58
Vulnerability Type: Indirect prompt injection through unvalidated upstream metadata
Risk Level: MediumVulnerable Code
The shared response normalizer marks external content as wrapped but copies upstream metadata without wrapping or element validation:
js externalContent: { untrusted: true, source: "web_search", provider: params.provider, wrapped: true }, results }; if (typeof response.search_id === "string") payload.searchId = response.search_id; if (typeof response.session_id === "string") payload.sessionId = response.session_id; if (Array.isArray(response.warnings) && response.warnings.length > 0) payload.warnings = response.warnings; if (Array.isArray(response.usage) && response.usage.length > 0) payload.usage = response.usage; const cachePayload = !request.sessionId && "sessionId" in payload ? { ...payload } : payload; if (!request.sessionId) delete cachePayload.sessionId;The free provider forwards these metadata fields directly from the remote MCP payload in
dist/.setup/parallel-free-web-search-provider.runtime-D1ws2w9J.mjs, lines 159–167:js const results = (Array.isArray(payload.results) ? payload.results : []).slice(0, Math.max(params.maxResults, 1)); return { search_id: typeof payload.search_id === "string" ? payload.search_id : void 0, session_id: sessionId, results, warnings: payload.warnings, usage: payload.usage };Technical Analysis
The normalizer protects search titles and excerpts with
wrapWebContent, but applies only an array check toresponse.warningsandresponse.usage. These arrays can therefore contain arbitrary strings or nested objects that are copied unchanged into model-visible tool results.This creates an inconsistent external-content boundary: the payload declares
wrapped: true, although some upstream-controlled content is not wrapped. The ...[truncated 2062 chars]
