T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/tencent_meeting_export.py:428
- Finding
- Destination Validation Does Not Prevent Navigation to Arbitrary URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tencent_meeting_export.py:428-435`, with the navigation sink at `scripts/tencent_meeting_export.py:231-234` **Vulnerability Type**: Non-enforcing URL validation and unrestricted browser navigation **Risk Level**: Medium ### Vulnerable Code ```python if not re.match(r"https?://meeting\.tencent\.com/", args.url): print(f"警告: URL 不像是腾讯会议链接: {args.url}") print(" 预期格式: https://meeting.tencent.com/cw/xxxxx") # 抓取数据 capture = TranscriptCapture( url=args.url, timeout=args.timeout, verbose=not args.quiet, ) ``` The untrusted URL is later passed directly to the browser: ```python await page.goto( self.url, wait_until="networkidle", timeout=self.timeout * 1000, ) ``` ### Technical Analysis The regular-expression check only produces a warning. It does not reject the URL, terminate execution, or replace it with an approved destination. Therefore, any URL accepted by Playwright can reach `page.goto()`. This violates the Skill's documented trust boundary, which states that it processes Tencent Meeting public share links. The launched browser uses the host's network connectivity and executes JavaScript supplied by the destination. An attacker-controlled page can consequently cause browser requests to external services or to network resources reachable from the host. The response listener also processes responses by matching endpoint substrings such as `minutes/detail` and `get-full-summary`, without first requiring the response origin to be Tencent Meeting. An attacker-controlled page could therefore return crafted JSON from similarly named endpoints, although the captured data is only formatted and written to output files in the audited implementation. ### Attack Path 1. An attacker supplies a URL that is not hosted at `meeting.tencent.com`, such as an attacker-controlled HTTP(S) page or a reachable internal web application. 2. The user or agent invokes the export script wit ...[truncated 1319 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse the supplied value using `urllib.parse.urlparse` rather than relying only on a regular expression. 2. Require all of the following conditions: - The scheme is exactly `https`. - The normalized hostname is exactly `meeting.tencent.com`. - No username or password is embedded in the URL. - The port is absent or explicitly approved. - The path begins with an approved Tencent Meeting share-link prefix, such as `/cw/`. 3. Raise an error and terminate before launching Chromium when any validation check fails. 4. Validate the final URL after redirects and reject redirects to unapproved origins. 5. Restrict intercepted API responses to the exact approved Tencent Meeting origin, not merely URLs containing expected endpoint substrings. 6. Consider adding request interception that blocks loopback, link-local, private-network, and non-HTTPS destinations. 7. Add tests covering malformed hosts, embedded credentials, alternate ports, redirects, loopback addresses, private IP addresses, and attacker-controlled domains. A hardened validation pattern should follow this structure: ```python from urllib.parse import urlparse parsed = urlparse(args.url) if ( parsed.scheme != "https" or parsed.hostname != "meeting.tencent.com" or parsed.username is not None or parsed.password is not None or parsed.port not in (None, 443) or not parsed.path.startswith("/cw/") ): raise ValueError("Only approved Tencent Meeting HTTPS share URLs are allowed") ``` ]]>
