T09 · Insecure Skill Coding Practices
- Location
scripts/fetch_news.py:20- Finding
Global TLS Certificate and Hostname Verification Disabled
- Content
View full analysis
Vulnerability Details
File Location:
scripts/fetch_news.py, lines 20–22 and 41
Vulnerability Type: Improper TLS certificate validation
Risk Level: MediumVulnerable Code
python # Ignore SSL certificates for some news sources ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONEThe insecure context is then used for every outbound request:
python def http_get(url, timeout=15): req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=timeout, context=ctx) as resp: return resp.read().decode("utf-8", errors="ignore")Technical Analysis
The script creates a global TLS context that disables both certificate-chain verification and hostname validation. Although all configured sources use HTTPS, passing this context to
urlopenremoves HTTPS server-authentication guarantees.An attacker able to intercept or redirect network traffic can present an arbitrary certificate without causing the connection to fail. The attacker can then impersonate a configured news service and return manipulated JSON or HTML. The script treats the response as trusted input, extracts news titles and URLs, stores them in SQLite, and incorporates titles into generated narration.
The flaw applies to every request made through
http_get, not merely to a single source with a known certificate problem.Attack Path
- The victim runs
scripts/fetch_news.pyon an attacker-influenced network, or an attacker compromises DNS, routing, or a network gateway. - The script initiates an HTTPS request to a configured news source.
- The attacker intercepts the request and supplies an arbitrary TLS certificate.
- Because certificate and hostname verification are disabled, the client accepts the attacker's endpoint.
- The attacker returns crafted news JSON or HTML containing manipulated titles and links.
- The script parses and stores that content in `ne ...[truncated 873 chars]
- The victim runs
- Remediation
View remediation
Remediation Suggestions
- Remove the global insecure TLS configuration and rely on Python's default verified HTTPS behavior:
python def http_get(url, timeout=15): req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=timeout) as resp: return resp.read().decode("utf-8", errors="ignore")- If an explicit context is required, preserve certificate and hostname validation:
python ctx = ssl.create_default_context() def http_get(url, timeout=15): req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=timeout, context=ctx) as resp: return resp.read().decode("utf-8", errors="ignore")-
If a particular source has certificate failures, repair or replace that source rather than disabling verification globally. Where a private certificate authority is legitimately required, load only that trusted CA using
cafileorload_verify_locations. -
Add automated tests that verify requests fail for expired, self-signed, hostname-mismatched, and otherwise untrusted certificates.
-
Validate fetched content before it enters the publication pipeline. Enforce expected response types and schemas, reject unexpected link schemes or hosts where appropriate, and require human approval before externally publishing generated material.
