T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/roadshow-capture.py:42
- Finding
- Weak URL Validation Allows Corporate Email Disclosure to Attacker-Controlled Sites<![CDATA[ ## Vulnerability Details **File Location**: `scripts/roadshow-capture.py:42-49`, `scripts/netroadshow-capture.py:63-73`, and `scripts/dealroadshow-capture.py:49-60` **Vulnerability Type**: Improper URL and hostname validation **Risk Level**: High ### Vulnerable Code `scripts/roadshow-capture.py:42-49`: ```python url = args.url.lower() if "netroadshow.com" in url: script = get_script_dir() / "netroadshow-capture.py" elif "dealroadshow.com" in url or "dealroadshow.finsight.com" in url: script = get_script_dir() / "dealroadshow-capture.py" else: sys.exit(1) ``` `scripts/netroadshow-capture.py:63-73`: ```python page = ctx.new_page() print(f"1. Navigating to show URL...") page.goto(args.url, wait_until="networkidle", timeout=30000) time.sleep(2) print(f"2. Filling email: {args.email}") email_input = page.locator("#homeEmailInput").first email_input.fill(args.email) time.sleep(0.3) ``` `scripts/dealroadshow-capture.py:49-60`: ```python page = ctx.new_page() print("1. Loading...") page.goto(args.url, wait_until="networkidle", timeout=30000) time.sleep(2) print("2. Email + Launch...") page.locator("input[type='email']").first.fill(email) time.sleep(0.5) page.get_by_text("Launch Deal Roadshow").click() ``` ### Technical Analysis The dispatcher determines the platform using case-insensitive substring checks against the entire URL. A substring match does not establish that the destination hostname belongs to an approved roadshow service. For example, each of the following attacker-controlled URLs would satisfy the current routing logic: ```text https://attacker.example/?target=dealroadshow.com https://netroadshow.com.attacker.example/fake-show https://attacker.example/dealroadshow.com/login ``` After selecting a platform script, the supplied URL is passed directly to `page.goto()`. The scripts then locate an expected email field and populate it with the configured `NRS_EMAIL` value. The DealRoadShow workflow also clicks a launch contr ...[truncated 1673 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse URLs with `urllib.parse.urlsplit()` rather than searching the raw string. 2. Require the `https` scheme and reject embedded credentials, malformed hostnames, and unexpected ports. 3. Compare the normalized hostname against an explicit allowlist: ```python from urllib.parse import urlsplit PLATFORM_HOSTS = { "netroadshow": {"netroadshow.com", "www.netroadshow.com"}, "dealroadshow": { "dealroadshow.com", "www.dealroadshow.com", "dealroadshow.finsight.com", "finsight.com", "www.finsight.com", }, } def validated_hostname(raw_url): parsed = urlsplit(raw_url) hostname = (parsed.hostname or "").rstrip(".").lower() if parsed.scheme != "https": raise ValueError("Only HTTPS URLs are permitted") if parsed.username or parsed.password: raise ValueError("URLs containing credentials are not permitted") if not hostname: raise ValueError("The URL does not contain a valid hostname") return hostname ``` 4. Match only exact approved hosts. If subdomains are required, use boundary-aware checks such as `host == base` or `host.endswith("." + base)`. 5. Repeat destination validation inside both platform-specific scripts so direct invocation remains safe. 6. Validate redirect destinations before entering the email. Permit only the documented redirect chain and approved hosts. 7. Consider blocking requests to unrelated origins through Playwright routing where compatible with the roadshow applications. ]]>
