T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/main.py:18
- Finding
- TLS certificate verification is disabled while the command reports successful validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:18-31` and `scripts/main.py:270-292` **Vulnerability Type**: Improper certificate and hostname validation **Risk Level**: High ### Vulnerable Code ```python def get_certificate(hostname: str, port: int = 443, timeout: int = 10) -> Optional[bytes]: """Get SSL certificate from host.""" try: context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE with socket.create_connection((hostname, port), timeout=timeout) as sock: with context.wrap_socket(sock, server_hostname=hostname) as ssock: cert_der = ssock.getpeercert(binary_form=True) return cert_der except Exception as e: return None ``` The unauthenticated certificate retrieval is subsequently presented as validation: ```python def validate_command(args): """Handle validate command (basic chain validation).""" # Note: This is a simplified validation result = check_certificate(args.domain, args.port) if result['status'] not in ['valid', 'expiring_soon']: print(f"❌ Cannot validate: {result['error']}") return print(f"🔒 Basic validation for {result['domain']}:{result['port']}") print(f"✓ Certificate retrieved successfully") print(f"✓ Certificate is {'expired' if result['status'] == 'expired' else 'currently valid'}") print(f"✓ Issuer: {result['issuer']}") if result['days_remaining'] is not None: if result['days_remaining'] > 30: print(f"✓ Expiration: {result['days_remaining']} days remaining (good)") elif result['days_remaining'] > 0: print(f"⚠ Expiration: {result['days_remaining']} days remaining (renew soon)") else: print(f"✗ Expiration: Certificate expired {abs(result['days_remaining'])} days ago") if not CRYPTOGRAPHY_AVAILABLE: print("⚠ Advanced val ...[truncated 2761 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Preserve the secure defaults when performing validation: ```python context = ssl.create_default_context() context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = True ``` 2. Separate authenticated validation from diagnostic certificate retrieval: - The `validate` command must use a verification-enabled TLS context. - If the tool needs to inspect expired, self-signed, or otherwise invalid certificates, provide a separately named inspection mode. - Clearly label inspection results as unverified and never assign them a trusted `valid` status. 3. Return distinct result fields for: - Certificate parsing success - Validity-period status - Hostname match - Chain trust - Revocation status, if supported 4. Catch `ssl.SSLCertVerificationError` separately and expose its verification code and message without converting the result into a generic connection failure. 5. Ensure the `validate` command reports success only when chain verification and hostname verification both succeed. 6. Update `README.md` and `SKILL.md` so the documented validation guarantees exactly match the implemented checks. If revocation checking is not implemented, state that limitation explicitly. 7. Add tests using: - A trusted certificate for the correct hostname - A self-signed certificate - A trusted certificate for the wrong hostname - An expired certificate - An incomplete or untrusted chain ]]>
