T09 · Insecure Skill Coding Practices
Warning
- Location
- skill_script.py.txt:24
- Finding
- Source Credibility Validation Bypass Through URL Substring Matching<![CDATA[ ## Vulnerability Details **File Location**: `skill_script.py.txt`, lines 24-32 **Vulnerability Type**: Improper URL hostname validation **Risk Level**: Medium ### Vulnerable Code ```python HIGH_TRUST = ['.gov', '.edu', '.org', 'reuters.com', 'apnews.com', 'bloomberg.com'] @staticmethod def score_source(url: str, title: str) -> float: score = 0.5 # Base score if any(domain in url for domain in CredibilityEngine.HIGH_TRUST): score += 0.3 if "research" in url.lower() or "journal" in url.lower(): score += 0.1 return min(score, 1.0) ``` ### Technical Analysis The credibility engine determines whether a search result is associated with a trusted source by searching for trusted-domain strings anywhere in the complete URL. It does not parse the URL, normalize its hostname, or verify that the trusted domain is the registrable domain or a legitimate subdomain. Consequently, attacker-controlled URLs such as the following can receive an unjustified trust bonus: ```text https://reuters.com.attacker.example/article https://attacker.example/article?source=.gov https://attacker.example/research/apnews.com ``` The additional `"research"` and `"journal"` substring checks have the same weakness and can grant another credibility increase based only on attacker-controlled URL text. The resulting scores are averaged at lines 97-100 and directly affect whether the report labels a claim as `Supported` or `Mixed`. This creates an integrity vulnerability in the skill's principal verification function. ### Attack Path 1. An attacker publishes misleading content on a domain under their control. 2. The attacker places a trusted substring such as `reuters.com`, `.gov`, or `.edu` in the hostname, path, or query string. They can also include `research` or `journal` for an additional score increase. 3. The attacker optimizes or promotes the page so that DuckDuckGo returns it for a targeted claim. 4. The skill accepts the result URL and pas ...[truncated 801 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse URLs with `urllib.parse.urlparse` and evaluate only the normalized hostname. 2. Require exact hostname matches or dot-boundary subdomain matches. For example, trust `reuters.com` and `www.reuters.com`, but reject `reuters.com.attacker.example`. 3. Maintain explicit trusted hostnames rather than broad textual markers such as `.org`, `.gov`, and `.edu`. 4. Reject malformed URLs and URLs without an expected `http` or `https` scheme. 5. Do not increase source credibility because words such as `research` or `journal` appear in a URL. Validate publisher identity and evidence quality independently. 6. Avoid interpreting domain reputation as proof that a claim is supported. Assess whether each source's content actually supports, contradicts, or merely mentions the claim. 7. Add unit tests covering deceptive hostnames, trusted strings in paths and queries, mixed-case hostnames, user-information components, and legitimate subdomains. A safer hostname check could follow this pattern: ```python from urllib.parse import urlparse TRUSTED_HOSTS = { "reuters.com", "apnews.com", "bloomberg.com", } def is_trusted_host(url: str) -> bool: parsed = urlparse(url) if parsed.scheme not in {"http", "https"}: return False hostname = (parsed.hostname or "").rstrip(".").lower() return any( hostname == trusted or hostname.endswith("." + trusted) for trusted in TRUSTED_HOSTS ) ``` ]]>
