Skip to content

fix: redact the zone password from browser connection errors - #170

Open
karaposu wants to merge 1 commit into
brightdata:mainfrom
karaposu:fix/redact-browser-credentials
Open

fix: redact the zone password from browser connection errors#170
karaposu wants to merge 1 commit into
brightdata:mainfrom
karaposu:fix/redact-browser-credentials

Conversation

@karaposu

Copy link
Copy Markdown

Problem

The scraping-browser CDP endpoint embeds the zone password in the URL userinfo (wss://brd-customer-…-zone-…:PASSWORD@brd.superproxy.io:9222 — the format the proxy protocol requires). When a connection attempt fails, Playwright quotes that endpoint verbatim, password included, in the error — in message, in stack, and in an enumerable log array of ws call-log lines (verified against a live connectOverCDP failure; the password appears four times).

browser_session.js both logged that raw error object and re-threw it. And because every browser tool calls get_page() outside its try, the raw error is not wrapped in UserError — it propagates to fastmcp, which puts error.message into the client-visible failure text. So a routine connection drop (the reconnect path exists because they're routine) can print the zone password in plaintext to:

  1. the server's stderr log — which MCP clients capture to disk and users paste into public bug reports;
  2. the MCP client, inside the tool-error text.

Same defect class as the scrape_batch bearer-token leak addressed in #163 — this is its browser-path twin.

Fix

  • redact_credentials() — a format-based scrubber (wss://user:PASSWORD@wss://user:***@) that keeps host and customer/zone id for debugging;
  • Browser_session._sanitize() — applies the regex and removes the session's exact password (parsed structurally from its own endpoint), so a password containing / or @ can't leave a fragment;
  • every error log site in the module goes through _sanitize;
  • the connection path throws a fresh Error(sanitized message) instead of re-throwing the Playwright object — a new Error carries no log array and a clean stack, so no carrier survives to any downstream sink.

Behaviour note

The client-visible connection-failure text now shows :***@ in place of the password; the diagnostic core (connect ECONNREFUSED …, zone/customer id) is preserved. Nothing in the codebase matches on the raw Playwright message or error type.

Tests

test/redact-credentials.test.js: the scrubber against the real captured Playwright error text; idempotency/no-op cases; an exotic-charset password (pa/ss@word); and an integration test driving a real connectOverCDP failure through get_browser, asserting the propagated error contains no trace of the password in message, stack, or any enumerable property.

Notes

Independent of #163 (no shared commits); only touches browser_session.js + tests.

When a Bright Data scraping-browser connection fails, Playwright quotes the
CDP endpoint URL -- which embeds the zone password in its userinfo
(wss://<customer-zone>:<password>@brd.superproxy.io) -- verbatim in the
error's message, stack, AND an enumerable `log` array. browser_session.js
both logged that raw error and re-threw it, so the password reached three
sinks: the server's stderr log, and -- because browser tools call get_page
outside their try, so the raw error is not wrapped in UserError -- tool_fn's
stack log and the fastmcp error surfaced to the MCP client.

Add redact_credentials() (a wss://user:pass@ -> wss://user:***@ scrubber)
and Browser_session._sanitize(), which also removes the session's exact
password read structurally from its endpoint, so a password containing '/'
or '@' cannot leave a fragment. Route every error log through it, and on the
connection path throw a fresh Error(sanitized message) instead of the
Playwright error -- a new Error carries no `log` array, a clean stack, and a
redacted message, closing every sink including the latent one.

Behaviour change: the connection-failure error text shown to the client is
now redacted (password -> ***); the diagnostic core (connect ECONNREFUSED,
etc.) is preserved. No caller depends on the raw Playwright error type or
message.

This is the browser-path twin of the scrape_batch bearer-token leak closed
in brightdata#163.

Adds test/redact-credentials.test.js: regex unit tests, an exotic-charset
case, and an integration test asserting a real connection failure propagates
an error with no password in message, stack, or enumerable props.
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