T09 · Insecure Skill Coding Practices
Warning
- Location
- watchdog.py:171
- Finding
- HTTPS and SSL Monitoring Disables TLS Certificate Validation<![CDATA[ ## Vulnerability Details **File Location**: `watchdog.py:171-174` and `watchdog.py:274-277` **Vulnerability Type**: Improper certificate validation (CWE-295) **Risk Level**: Medium ### Vulnerable Code HTTPS endpoint monitoring disables hostname and certificate verification: ```python ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE req = urllib.request.Request(target, method='HEAD') with urllib.request.urlopen(req, context=ctx, timeout=timeout) as resp: ``` The SSL certificate check repeats the same insecure configuration: ```python ctx = ssl_module.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl_module.CERT_NONE with socket.create_connection((host, 443), timeout=10) as sock: with ctx.wrap_socket(sock, server_hostname=host) as ssock: ``` ### Technical Analysis `ssl.create_default_context()` initially enables secure certificate-chain and hostname validation. The subsequent assignments explicitly disable both controls: - `check_hostname = False` permits a certificate issued for an unrelated hostname. - `verify_mode = ssl.CERT_NONE` permits self-signed, expired, revoked, untrusted, or attacker-generated certificates. Consequently, HTTPS health checks validate only whether an endpoint returns a response; they do not establish that the response came from the intended authenticated server. The SSL-specific monitor similarly establishes an unauthenticated TLS connection, contradicting the documented SSL-validity monitoring purpose. The certificate-expiry implementation also calls `getpeercert_der()`, which is not a standard Python `SSLSocket` method, and attempts to find `notAfter=` inside PEM output. This does not reliably extract or validate the certificate expiration date. Although exceptions are converted into a warning, the monitor cannot provide the advertised trustworthy expiry assessment. ### Attack Path 1. An administrator configures an HTTPS monitor for a sensi ...[truncated 1297 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Preserve the secure defaults from `ssl.create_default_context()` by removing: ```python ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE ``` 2. Perform HTTPS requests using a validated TLS context: ```python ctx = ssl.create_default_context() req = urllib.request.Request(target, method='HEAD') with urllib.request.urlopen(req, context=ctx, timeout=timeout) as resp: ... ``` 3. For certificate-expiry monitoring, establish a verified TLS connection and retrieve the parsed peer certificate: ```python ctx = ssl.create_default_context() with socket.create_connection((host, port), timeout=10) as sock: with ctx.wrap_socket(sock, server_hostname=host) as ssock: cert = ssock.getpeercert() not_after = cert["notAfter"] expires_at = datetime.strptime( not_after, "%b %d %H:%M:%S %Y %Z" ) ``` 4. Parse the configured port instead of always connecting to port 443. 5. Distinguish certificate failures from availability failures in stored results, including hostname mismatch, untrusted issuer, expiration, and connection timeout. 6. If monitoring intentionally needs to support private certificate authorities, provide a configurable CA bundle rather than disabling verification globally. 7. Add automated tests using valid, expired, self-signed, and hostname-mismatched certificates. Tests should confirm that invalid certificates cannot produce an `up` result. ]]>
