T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/hh_apply_batch.py:187
- Finding
- Unrestricted Browser Navigation Allows JavaScript URL Execution in an Authenticated Tab<![CDATA[ ## Vulnerability Details **File Location**: `scripts/hh_apply_batch.py:187-196` **Supporting Sink**: `scripts/hh_browser_cli.py:89-96` **Vulnerability Type**: Missing URL scheme, hostname, and browser-tab validation **Risk Level**: High ### Vulnerable Code ```python browser = BrowserCli(profile=args.profile) try: browser.ensure_ready() target_id = browser.current_target() current = browser.current_page(target_id).result or {} origin = str(current.get("origin") or "https://hh.ru") results: list[dict[str, Any]] = [] for url in args.urls: normalized = re.sub(r"^https?://[^/]+", origin, url) browser.navigate_js(normalized, target_id) ``` The navigation sink is: ```python def navigate_js(self, url: str, target_id: str | None = None) -> BrowserResult: payload = json.dumps(url, ensure_ascii=False) try: return self.evaluate(f"() => {{ window.location.href = {payload}; return {{navigatingTo: {payload}}}; }}", target_id) except BrowserCliError as e: msg = str(e) if "Execution context was destroyed" in msg or "ERR_ABORTED" in msg: return BrowserResult({"ok": True, "result": {"navigatingTo": url}}) raise ``` The target selection also uses the first attached tab without validating its origin: ```python def current_target(self) -> str: tabs = self.tabs().get("tabs") or [] if not tabs: raise BrowserCliError(f"browser profile {self.profile!r} has no attached tabs") return tabs[0]["targetId"] ``` ### Technical Analysis The application workflow states that positional arguments are HH vacancy URLs, but it does not parse or validate their URL scheme or hostname. The regular expression only rewrites values beginning with an HTTP or HTTPS origin: ```python re.sub(r"^https?://[^/]+", origin, url) ``` Consequently, a non-HTTP value such as `javascript:<payload>` remains unchanged. The value is then assigned to `window.location.href` inside an attac ...[truncated 2665 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse every supplied URL with `urllib.parse.urlsplit()` before navigation. 2. Require the `https` scheme and reject all other schemes, including: - `javascript` - `data` - `file` - `blob` - `vbscript` 3. Enforce an explicit hostname allowlist, such as `hh.ru` and specifically approved HH subdomains. 4. Reject URLs containing: - Embedded usernames or passwords - Unexpected ports - Backslash-based authority confusion - Empty or malformed hostnames 5. Verify the final parsed URL again after any normalization. 6. Do not derive the navigation origin from an arbitrary currently selected tab. 7. Enumerate attached tabs and explicitly select one whose parsed hostname belongs to the HH allowlist. 8. Abort if no verified HH tab is attached. 9. Add a defense-in-depth check in `BrowserCli.navigate_js()` so dangerous schemes are rejected even if a caller fails to validate them. 10. Add regression tests for `javascript:`, `data:`, mixed-case schemes, whitespace-prefixed schemes, malformed authorities, unrelated domains, and an unrelated first tab. ]]>
