Severity Assessment
CVSS Assessment
| Metric |
v3.1 |
v4.0 |
| Score |
9.9 / 10.0 |
9.4 / 10.0 |
| Severity |
Critical |
Critical |
| Vector |
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L |
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L |
| Calculator |
CVSS v3.1 Calculator |
CVSS v4.0 Calculator |
Threat Model Alignment
Classification: security-specific
The config.get method is explicitly read-scoped (operator.read) and returns a redacted config snapshot to prevent credential disclosure. This finding demonstrates that the redaction layer fails to treat browser.cdpUrl and browser.profiles.*.cdpUrl as sensitive, leaking reusable third-party service credentials (Browserless/Browserbase API keys, HTTP Basic auth) to any authenticated read-scoped client. This crosses the redaction trust boundary: read-scoped callers are not supposed to see raw credentials in redacted snapshots.
This is not covered by the Out of Scope section. It is not a multi-tenant assumption (single-operator read-scope clients should still not see raw credentials in redacted snapshots), not a prompt injection chain, and not an operator-intended feature. The documentation at docs/tools/browser.md:277 explicitly states "Treat remote CDP URLs/tokens as secrets," yet the config redaction layer does not enforce this.
Impact
Authenticated clients with only operator.read scope can call config.get and receive the full, unredacted browser.cdpUrl and browser.profiles.*.cdpUrl values, including embedded query tokens (e.g., Browserless ?token=...) and HTTP Basic credentials (e.g., user:pass@host). The leaked credentials are reusable outside OpenClaw to connect directly to the upstream browser service, bypassing OpenClaw's audit trail and scope checks.
Affected Component
File: src/config/zod-schema.ts:358,386
// browser.cdpUrl — NOT registered with sensitive
cdpUrl: z.string().optional(),
// browser.profiles.*.cdpUrl — NOT registered with sensitive
cdpUrl: z.string().optional(),
File: src/config/redact-snapshot.ts:32-33
function isUserInfoUrlPath(path: string): boolean {
return path.endsWith(".baseUrl") || path.endsWith(".httpUrl");
}
File: src/config/schema.hints.ts:104-110
const SENSITIVE_PATTERNS = [
/token$/i,
/password/i,
/secret/i,
/api.?key/i,
/serviceaccount(?:ref)?$/i,
];
The cdpUrl field name does not match any sensitive pattern, is not registered as sensitive in the Zod schema, and isUserInfoUrlPath only strips userinfo from .baseUrl and .httpUrl paths -- not .cdpUrl paths. A separate redactCdpUrl helper exists at src/browser/cdp.helpers.ts:42-58 but is only used in CLI status output and logging, not in the config snapshot redaction path.
Technical Reproduction
- Configure a remote browser profile with an auth-bearing CDP URL:
{ browser: { profiles: { remote: { cdpUrl: "https://alice:secret@example.com/chrome?token=supersecret123" } } } }
- Connect a Gateway client that has only
operator.read scope.
- Call
config.get.
- Observe the response contains the full unredacted
cdpUrl in payload.config.browser.profiles.remote.cdpUrl, including the query token and Basic-auth userinfo.
Demonstrated Impact
The config redaction layer (redactConfigSnapshot at src/config/redact-snapshot.ts:382-431) is the single control point for stripping credentials before read-scoped API responses. It relies on two mechanisms: (1) schema-level sensitive registration via Zod's .register(sensitive), and (2) pattern-based fallback matching on field names via SENSITIVE_PATTERNS. Neither mechanism covers cdpUrl:
browser.cdpUrl and browser.profiles.*.cdpUrl are declared as plain z.string().optional() without .register(sensitive) (confirmed in src/config/zod-schema.ts:358,386).
- The field name
cdpUrl does not match any entry in SENSITIVE_PATTERNS (/token$/i, /password/i, /secret/i, /api.?key/i, /serviceaccount/i).
- The URL userinfo stripping (
isUserInfoUrlPath) only triggers for paths ending in .baseUrl or .httpUrl, not .cdpUrl.
- The generated config baseline confirms
"sensitive": false for both paths (docs/.generated/config-baseline.jsonl:702,716).
Meanwhile, OpenClaw's own documentation explicitly supports and encourages auth-bearing CDP URLs with query tokens (docs/tools/browser.md:168-175,210,250) and explicitly warns to "Treat remote CDP URLs/tokens as secrets" (docs/tools/browser.md:277). The leaked credentials are reusable outside OpenClaw: a read-scoped client can take the returned Browserless or Browserbase URL and open direct browser sessions against the upstream service, bypassing OpenClaw's scope checks and audit trail entirely.
Environment
Source review on commit e864421d83cf292d1dc238f5383f3ac4b011c924 (tag v2026.3.23-2). Affected whenever operators store auth-bearing remote CDP URLs in browser.cdpUrl or browser.profiles.*.cdpUrl and expose config.get to read-scoped clients.
Remediation Advice
Register browser.cdpUrl and browser.profiles.*.cdpUrl as sensitive in the Zod schema (add .register(sensitive) to both declarations in src/config/zod-schema.ts), and extend isUserInfoUrlPath in src/config/redact-snapshot.ts to also match .cdpUrl paths so that embedded URL userinfo is stripped even when the full value is not sentinel-redacted. This aligns the config redaction layer with the documentation guidance that CDP URLs should be treated as secrets.
Severity Assessment
CVSS Assessment
Threat Model Alignment
Classification:
security-specificThe
config.getmethod is explicitly read-scoped (operator.read) and returns a redacted config snapshot to prevent credential disclosure. This finding demonstrates that the redaction layer fails to treatbrowser.cdpUrlandbrowser.profiles.*.cdpUrlas sensitive, leaking reusable third-party service credentials (Browserless/Browserbase API keys, HTTP Basic auth) to any authenticated read-scoped client. This crosses the redaction trust boundary: read-scoped callers are not supposed to see raw credentials in redacted snapshots.This is not covered by the Out of Scope section. It is not a multi-tenant assumption (single-operator read-scope clients should still not see raw credentials in redacted snapshots), not a prompt injection chain, and not an operator-intended feature. The documentation at
docs/tools/browser.md:277explicitly states "Treat remote CDP URLs/tokens as secrets," yet the config redaction layer does not enforce this.Impact
Authenticated clients with only
operator.readscope can callconfig.getand receive the full, unredactedbrowser.cdpUrlandbrowser.profiles.*.cdpUrlvalues, including embedded query tokens (e.g., Browserless?token=...) and HTTP Basic credentials (e.g.,user:pass@host). The leaked credentials are reusable outside OpenClaw to connect directly to the upstream browser service, bypassing OpenClaw's audit trail and scope checks.Affected Component
File:
src/config/zod-schema.ts:358,386File:
src/config/redact-snapshot.ts:32-33File:
src/config/schema.hints.ts:104-110The
cdpUrlfield name does not match any sensitive pattern, is not registered as sensitive in the Zod schema, andisUserInfoUrlPathonly strips userinfo from.baseUrland.httpUrlpaths -- not.cdpUrlpaths. A separateredactCdpUrlhelper exists atsrc/browser/cdp.helpers.ts:42-58but is only used in CLI status output and logging, not in the config snapshot redaction path.Technical Reproduction
operator.readscope.config.get.cdpUrlinpayload.config.browser.profiles.remote.cdpUrl, including the query token and Basic-auth userinfo.Demonstrated Impact
The config redaction layer (
redactConfigSnapshotatsrc/config/redact-snapshot.ts:382-431) is the single control point for stripping credentials before read-scoped API responses. It relies on two mechanisms: (1) schema-levelsensitiveregistration via Zod's.register(sensitive), and (2) pattern-based fallback matching on field names viaSENSITIVE_PATTERNS. Neither mechanism coverscdpUrl:browser.cdpUrlandbrowser.profiles.*.cdpUrlare declared as plainz.string().optional()without.register(sensitive)(confirmed insrc/config/zod-schema.ts:358,386).cdpUrldoes not match any entry inSENSITIVE_PATTERNS(/token$/i,/password/i,/secret/i,/api.?key/i,/serviceaccount/i).isUserInfoUrlPath) only triggers for paths ending in.baseUrlor.httpUrl, not.cdpUrl."sensitive": falsefor both paths (docs/.generated/config-baseline.jsonl:702,716).Meanwhile, OpenClaw's own documentation explicitly supports and encourages auth-bearing CDP URLs with query tokens (
docs/tools/browser.md:168-175,210,250) and explicitly warns to "Treat remote CDP URLs/tokens as secrets" (docs/tools/browser.md:277). The leaked credentials are reusable outside OpenClaw: a read-scoped client can take the returned Browserless or Browserbase URL and open direct browser sessions against the upstream service, bypassing OpenClaw's scope checks and audit trail entirely.Environment
Source review on commit
e864421d83cf292d1dc238f5383f3ac4b011c924(tagv2026.3.23-2). Affected whenever operators store auth-bearing remote CDP URLs inbrowser.cdpUrlorbrowser.profiles.*.cdpUrland exposeconfig.getto read-scoped clients.Remediation Advice
Register
browser.cdpUrlandbrowser.profiles.*.cdpUrlas sensitive in the Zod schema (add.register(sensitive)to both declarations insrc/config/zod-schema.ts), and extendisUserInfoUrlPathinsrc/config/redact-snapshot.tsto also match.cdpUrlpaths so that embedded URL userinfo is stripped even when the full value is not sentinel-redacted. This aligns the config redaction layer with the documentation guidance that CDP URLs should be treated as secrets.