T09 · Insecure Skill Coding Practices
Error
- Location
- watchdog.py:171
- Finding
- TLS Certificate Validation Is Explicitly Disabled<![CDATA[ ## Vulnerability Details **File Location**: `watchdog.py:171-174` and `watchdog.py:261-265` **Vulnerability Type**: Improper certificate validation **Risk Level**: High ### Vulnerable Code HTTP monitoring disables certificate-chain and hostname 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: elapsed = (time.time() - start) * 1000 status_code = resp.status return ('up', elapsed, f'HTTP {status_code}') ``` The dedicated certificate monitor repeats the 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: cert_der = ssock.getpeercert_der() import ssl as ssl_module cert = ssl_module.DER_cert_to_PEM_cert(cert_der) # Simple extraction import re match = re.search(r'notAfter=(.*?)[\r\n]', cert, re.DOTALL) if match: return ('up', 0, f'Certificate valid') ``` ### Technical Analysis Setting `check_hostname` to `False` and `verify_mode` to `ssl.CERT_NONE` disables the two principal controls used to authenticate a TLS server: 1. Validation of the certificate chain against trusted certificate authorities. 2. Verification that the certificate identity matches the requested hostname. Consequently, HTTPS monitoring accepts self-signed, expired, hostname-mismatched, and attacker-issued certificates. A successful TLS connection can therefore cause a monitored service to be reported as available even when the connection was intercepted. The certificate-expiry implementation is also unreliable. It calls `SSLSocket.getpeercert_der()`, which is not the standard Python API for obtaining ...[truncated 1421 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Preserve the secure defaults provided by `ssl.create_default_context()`: ```python ctx = ssl.create_default_context() ``` Remove both `ctx.check_hostname = False` and `ctx.verify_mode = ssl.CERT_NONE`. 2. Use the validated context for HTTPS requests and treat certificate-validation failures as a failed check. 3. Retrieve the peer certificate using the supported API: ```python cert_der = ssock.getpeercert(binary_form=True) ``` 4. Parse the certificate with a maintained X.509 implementation, such as `cryptography.x509`, rather than applying a regular expression to PEM data. 5. Compare the parsed `not_valid_after_utc` value with the configured warning threshold and distinguish valid, warning, expired, and validation-failure states. 6. Add automated tests for trusted certificates, self-signed certificates, expired certificates, hostname mismatches, and certificates nearing expiration. ]]>
