T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/scrapling_scrape.py:48
- Finding
- Unrestricted URL Fetching Enables Access to Internal Network Resources<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scrapling_scrape.py:48-83` **Additional Locations**: `scripts/scrapling_smoke_test.py:70-120`, `SKILL.md:35-42`, `SKILL.md:76-96`, `references/mcp-setup.md:47-78`, `references/mcp-setup.md:121-136` **Vulnerability Type**: Unrestricted URL fetching / server-side request forgery risk **Risk Level**: Medium ### Vulnerable Code ```python p.add_argument("--url", required=True) p.add_argument("--mode", choices=["fetcher", "dynamic", "stealthy"], default="fetcher") p.add_argument("--css", help="CSS selector (supports ::text and ::attr())") p.add_argument("--xpath", help="XPath selector") p.add_argument("--first", action="store_true", help="Return only the first match") p.add_argument("--headless", action="store_true", help="Headless browser (dynamic/stealthy)") p.add_argument("--solve-cloudflare", action="store_true", help="Attempt to solve Cloudflare (stealthy session)") p.add_argument("--network-idle", action="store_true", help="Wait for network idle (dynamic session)") p.add_argument("--adaptive", action="store_true", help="Use adaptive selectors (if supported)") p.add_argument("--auto-save", action="store_true", help="Auto-save selector fingerprints (if supported)") p.add_argument("--pretty", action="store_true", help="Pretty-print JSON") args = p.parse_args() if not args.css and not args.xpath: _die("Provide --css or --xpath") url = args.url try: # Sessions are more reliable than one-shot fetchers for anything non-trivial. from scrapling.fetchers import FetcherSession, DynamicSession, StealthySession except Exception: _die( "Scrapling is not installed in this Python environment. Try:\n" " python3 -m pip install scrapling\n" "If you need browser-based fetching, you may also need:\n" " python3 -m playwright install chromium" ) if args.mode == "fetcher": with FetcherSession(impersonate="chrome") as session: page = session.get(url, ...[truncated 4286 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only explicitly supported schemes, normally `https` and optionally `http`. 2. Parse URLs using a standards-compliant parser and reject embedded credentials, malformed hosts, ambiguous numeric IP representations, and unexpected ports where appropriate. 3. Resolve the hostname before connecting and reject every resolved address that is: - Loopback. - Private. - Link-local. - Reserved. - Multicast. - Unspecified. 4. Explicitly deny known cloud metadata hostnames and addresses. 5. Apply the same checks to IPv4 and IPv6 addresses. 6. Revalidate every redirect target before following it. 7. Use a network egress proxy or firewall to enforce the policy independently of application-level validation. 8. Prefer a hostname allowlist when the Skill is used autonomously by an agent. 9. Mitigate DNS rebinding by connecting only to validated resolved addresses or by enforcing restrictions at the egress layer. 10. Add strict request timeouts, response-size limits, redirect limits, and crawl budgets. 11. Require explicit user confirmation before accessing non-public or newly encountered domains. 12. Document that URLs obtained from webpages or model output are untrusted input. ]]>
