T09 · Insecure Skill Coding Practices
Warning
- Location
- code.md:15
- Finding
- Fail-Open robots.txt Validation Permits Scraping Without Confirmed Authorization<![CDATA[ ## Vulnerability Details **File Location**: `code.md`, lines 15-18 **Vulnerability Type**: Fail-open authorization and compliance check **Risk Level**: Medium ### Complete Code Snippet ```python try: rp.read() except Exception: return True # No robots.txt = allowed ``` ### Technical Analysis The `can_scrape` implementation treats every exception raised while retrieving or parsing `robots.txt` as permission to scrape. The exception handler does not distinguish a confirmed absence of a robots file from DNS errors, TLS failures, connection timeouts, access-denied responses, malformed content, or parser failures. This is a fail-open control: when the mechanism responsible for determining whether access is permitted cannot reach a reliable decision, it authorizes the operation. It also conflicts with the Skill's stated policy that robots.txt must be checked before scraping. ### Attack Path 1. The scraper is given a target URL. 2. The target's `robots.txt` request fails because of a network error, TLS problem, malformed response, or deliberate disruption. 3. `RobotFileParser.read()` raises an exception. 4. The broad `except Exception` handler returns `True`. 5. The caller interprets the result as authorization and proceeds to scrape the target without successfully evaluating its robots.txt policy. ### Impact Assessment An affected scraper can access paths without confirming that automated access is allowed. This does not directly grant operating-system privileges or establish code execution, but it bypasses the Skill's intended access-policy gate and may cause unauthorized requests, terms-of-service violations, blocking of the scraper's network identity, or legal and compliance exposure. ]]>
- Remediation
- <![CDATA[ ## Remediation Suggestions - Fail closed when robots.txt cannot be reliably retrieved or parsed. - Return a tri-state result such as `ALLOWED`, `DISALLOWED`, or `INDETERMINATE` rather than conflating errors with authorization. - Permit scraping only when the result is explicitly `ALLOWED`. - Distinguish a confirmed HTTP 404 response from network, TLS, authorization, server, and parsing failures. - Set explicit connection and read timeouts. - Log the failure reason without exposing credentials or sensitive query parameters. - Require explicit operator approval before proceeding after an indeterminate result. Example hardened behavior: ```python from enum import Enum from urllib.robotparser import RobotFileParser from urllib.parse import urlparse class RobotsDecision(Enum): ALLOWED = "allowed" DISALLOWED = "disallowed" INDETERMINATE = "indeterminate" def can_scrape(url: str, user_agent: str = "*") -> RobotsDecision: parsed = urlparse(url) robots_url = f"{parsed.scheme}://{parsed.netloc}/robots.txt" rp = RobotFileParser() rp.set_url(robots_url) try: rp.read() except Exception: return RobotsDecision.INDETERMINATE return ( RobotsDecision.ALLOWED if rp.can_fetch(user_agent, url) else RobotsDecision.DISALLOWED ) ``` ]]>
