Skip to content

security: sanitize Perplexity API error messages (CWE-200; re-impl of #103)#107

Open
jliounis wants to merge 1 commit into
mainfrom
jliounis/sanitize-api-errors
Open

security: sanitize Perplexity API error messages (CWE-200; re-impl of #103)#107
jliounis wants to merge 1 commit into
mainfrom
jliounis/sanitize-api-errors

Conversation

@jliounis
Copy link
Copy Markdown
Collaborator

Summary

Re-implementation of the previously-closed #103. Credit: @sebastiondev for the original analysis and patch.

Vulnerability

CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) — Medium severity.

makeApiRequest, performChatCompletion, and performSearch previously embedded raw upstream details into thrown Error messages:

throw new Error(`Network error while calling Perplexity API: ${error}`);
throw new Error(`Perplexity API error: ${status} ${statusText}\n${errorText}`);
throw new Error(`Failed to parse JSON response from Perplexity API: ${error}`);

The MCP SDK returns thrown tool errors verbatim to remote callers in result.content[].text. Because this server can also run as an unauthenticated HTTP service bound to 0.0.0.0, a remote MCP client can trigger upstream failures and read back:

  • the upstream response body (provider internal traces, account hints, etc.)
  • raw exception text from the network layer (proxy/DNS details, internal hostnames)
  • raw JSON-parse exception text (may include partial payloads)

Fix

Separate operator diagnostics from caller-visible errors:

  • The full upstream body, parser exception, and network exception text are now logged server-side via the existing logger (writes to stderr; survives STDIO transport).
  • The Error that bubbles up to the MCP SDK now contains only a stable, generic, non-secret message:
    • Perplexity API error: <status> <statusText>
    • Network error while calling Perplexity API
    • Failed to parse JSON response from Perplexity API
    • Failed to parse JSON response from Perplexity Search API
  • Timeout and validation errors are unchanged (they were already sanitized).

Tests

  • Updated should handle error text parse failures to assert the sanitized output and the absence of the underlying exception text.
  • Added 3 new CWE-200 regression tests:
    • JSON parse error must not leak parser exception text
    • Network error must not leak network exception text
    • Upstream 4xx/5xx must not leak the response body or trace
  • npm test: 81 passed / 81 (was 78 on main).
  • npm run build: clean.

Backward compatibility

  • The status + statusText prefix and the four generic strings are preserved exactly as before, so any client that pattern-matches on "Perplexity API error: 401" etc. continues to work.
  • The only thing removed is the trailing detail block — which was the leaky part.

Re-implementation of #103. Credit: @sebastiondev for the original
analysis and patch.

Problem
-------
makeApiRequest, performChatCompletion, and performSearch previously
embedded raw upstream details into thrown Error messages:

  throw new Error(`Network error while calling Perplexity API: ${error}`);
  throw new Error(`Perplexity API error: ${status} ${statusText}\n${errorText}`);
  throw new Error(`Failed to parse JSON response from Perplexity API: ${error}`);

The MCP SDK returns thrown tool errors verbatim to remote callers in
`result.content[].text`. Because this server can also run as an
unauthenticated HTTP service bound to 0.0.0.0, a remote MCP client could
trigger upstream failures and read back:

  - the upstream response body (provider internal traces, account hints)
  - raw exception text from the network layer (proxy/DNS details, etc.)
  - raw JSON-parse exception text (may include partial payloads)

That is CWE-200 (Exposure of Sensitive Information to an Unauthorized
Actor): medium severity, reachable via the HTTP transport, mitigable
without losing operator visibility.

Fix
---
Separate operator diagnostics from caller-visible errors:

  - The full upstream body, parser exception, and network exception
    text are now logged server-side via the existing structured logger
    (writes to stderr; survives STDIO transport).
  - The Error that bubbles up to the MCP SDK now contains only a stable,
    generic, non-secret message:
      "Perplexity API error: <status> <statusText>"
      "Network error while calling Perplexity API"
      "Failed to parse JSON response from Perplexity API"
      "Failed to parse JSON response from Perplexity Search API"
  - Timeout and validation errors are unchanged (they were already
    sanitized).

Tests
-----
- Updated "should handle error text parse failures" to assert the new
  sanitized output and the absence of the underlying exception text.
- Added 3 new CWE-200 regression tests:
    * JSON parse error must not leak parser exception text
    * Network error must not leak network exception text
    * Upstream 4xx/5xx must not leak the response body
- npm test: 81 passed / 81 (was 78 on main).
- npm run build: clean.

Co-authored-by: @sebastiondev
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.

2 participants