T09 · Insecure Skill Coding Practices
- Location
scripts/control_host_browser.sh:20- Finding
Unrestricted URL Schemes Reach the Host Browser Through CDP
- Content
View full analysis
Vulnerability Details
File Location:
scripts/control_host_browser.sh:20-21, 52; data reaches the navigation sink atscripts/cdp_navigate.py:61-65
Vulnerability Type: Missing URL scheme and destination validation
Risk Level: MediumVulnerable Code
scripts/control_host_browser.sh:20-21, 52:bash PROFILE=$1 URL=$2 # Navigate using Python CDP script python3 "$SCRIPT_DIR/cdp_navigate.py" "$PORT" "$PAGE_ID" "$URL"scripts/cdp_navigate.py:61-65:python command = json.dumps({ 'id': 1, 'method': 'Page.navigate', 'params': {'url': url} })Technical Analysis
The Skill documentation states that only HTTP and HTTPS URLs are supported, but this restriction is not enforced in either script. The shell script accepts its second argument as
URLand passes it unchanged to the Python program. The Python program then places that value directly into a Chrome DevTools ProtocolPage.navigatecommand.Shell quoting prevents this input from becoming shell command injection. Nevertheless, it does not constrain the URL scheme or destination. Depending on Chrome's CDP and browser security policies, inputs using non-web schemes or host-accessible destinations may therefore be attempted, including
file:, browser-internal schemes, loopback addresses, link-local addresses, and private-network services.This exceeds the minimum privilege implied by the documented feature because a Skill intended to open ordinary HTTP/HTTPS pages can ask the authenticated host-browser profile to access other resource classes.
Attack Path
- An attacker causes or persuades a user to request that the Skill open a crafted destination.
- The crafted value is supplied as the second argument to
control_host_browser.sh. - The shell script assigns the value to
URLwithout validation. - The value is passed unchanged to
cdp_navigate.py. - The Python script embeds it in the
Page.navigateCDP command. - Host Chrome attempts to naviga ...[truncated 931 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse and validate the destination before creating a new browser tab.
- Permit only the exact, case-normalized schemes
httpandhttps. - Require a syntactically valid hostname and reject URLs containing control characters or embedded credentials.
- If local-resource access is not required, resolve and reject loopback, link-local, private, multicast, unspecified, and other reserved IP ranges. Apply equivalent checks after DNS resolution and redirects to mitigate hostname-based bypasses and DNS rebinding.
- Consider maintaining an explicit hostname allowlist when the expected destination set is limited.
- Repeat validation in
cdp_navigate.pyso direct invocation cannot bypass checks in the shell wrapper. - Avoid printing complete URLs when query strings or fragments may contain credentials, tokens, or other sensitive data.
- Add tests covering
file:,chrome:,javascript:, malformed URLs, encoded control characters,localhost, IPv4 and IPv6 loopback, private IP ranges, and redirect-based bypass attempts.
The flagged Base64 operation in
scripts/cdp_navigate.pyis only used to construct a fixed WebSocket handshake key and does not encode or exfiltrate sensitive data. Thecurlinvocation inscripts/control_host_browser.shcontacts a fixed CDP endpoint and is not piped to a shell; no remote payload retrieval and execution was found.
