# PYTHON-LANG-SEC-051: Weak SSL/TLS Protocol Version

> **Severity:** HIGH | **CWE:** CWE-326 | **OWASP:** A02:2021

- **Language:** Python
- **Category:** Python Core
- **URL:** https://codepathfinder.dev/registry/python/lang/PYTHON-LANG-SEC-051
- **Detection:** `pathfinder scan --ruleset python/PYTHON-LANG-SEC-051 --project .`

## Description

SSL 2.0, SSL 3.0, TLS 1.0, and TLS 1.1 are deprecated protocol versions with known
cryptographic vulnerabilities that enable various attacks on TLS connections. These
protocols should not be enabled in any production system.

SSLv2 (DROWN attack), SSLv3 (POODLE attack), TLS 1.0/1.1 (BEAST, POODLE-TLS, SLOTH,
SWEET32) all have published attacks. NIST deprecated TLS 1.0 and 1.1 in 2018, and
PCI DSS required migration away from these versions by 2018.

Python's ssl module provides PROTOCOL_TLS_CLIENT and PROTOCOL_TLS_SERVER constants that
negotiate the highest mutually supported version (at least TLS 1.2 when properly
configured). SSLContext should be created with these constants, not with specific deprecated
version constants.


## Vulnerable Code

```python
import ssl
import http.client
import requests as http_requests

ctx2 = ssl.SSLContext(ssl.PROTOCOL_SSLv2)
```

## Secure Code

```python
import ssl

# INSECURE: Using deprecated protocol versions
# ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2)  # Not available in Python 3.10+
# ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv3)
# ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
# ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)

# SECURE: Use PROTOCOL_TLS_CLIENT for clients (verifies certificates)
def create_client_context() -> ssl.SSLContext:
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    ctx.minimum_version = ssl.TLSVersion.TLSv1_2
    return ctx

# SECURE: Use PROTOCOL_TLS_SERVER for servers with minimum TLS 1.3
def create_server_context(certfile: str, keyfile: str) -> ssl.SSLContext:
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ctx.minimum_version = ssl.TLSVersion.TLSv1_3
    ctx.load_cert_chain(certfile=certfile, keyfile=keyfile)
    return ctx

# SECURE: Use ssl.create_default_context() for client connections (recommended)
def make_secure_connection(host: str, port: int):
    ctx = ssl.create_default_context()
    # create_default_context() sets minimum version to TLS 1.2 by default
    return ctx

```

## Detection Rule (Python SDK)

```python
from rules.python_decorators import python_rule
from codepathfinder import calls, QueryType

class SSLModule(QueryType):
    fqns = ["ssl"]


@python_rule(
    id="PYTHON-LANG-SEC-051",
    name="Weak SSL/TLS Protocol Version",
    severity="HIGH",
    category="lang",
    cwe="CWE-326",
    tags="python,ssl,weak-tls,protocol-version,CWE-326",
    message="Weak SSL/TLS version detected (SSLv2/3 or TLSv1/1.1). Use TLS 1.2+ minimum.",
    owasp="A02:2021",
)
def detect_weak_ssl():
    """Detects SSLContext with weak protocol versions."""
    return SSLModule.method("SSLContext").where(0, "ssl.PROTOCOL_SSLv2")
```

## How to Fix

- Replace all deprecated protocol constants (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1) with PROTOCOL_TLS_CLIENT or PROTOCOL_TLS_SERVER.
- Set ctx.minimum_version = ssl.TLSVersion.TLSv1_2 or TLSv1_3 explicitly to prevent negotiation of older versions.
- Use ssl.create_default_context() for client connections, which configures secure defaults including minimum TLS version.
- Disable weak cipher suites by setting ctx.set_ciphers() with a strong cipher string excluding RC4, DES, 3DES, and export ciphers.
- Test TLS configuration with tools that verify protocol version support and cipher suite strength.

## Security Implications

- **POODLE Attack (SSLv3/TLS 1.0):** The POODLE (Padding Oracle On Downgraded Legacy Encryption) attack exploits CBC
padding oracle weaknesses in SSLv3 and some TLS 1.0 implementations. An attacker
performing a MITM can decrypt individual bytes of the ciphertext by making repeated
requests and observing padding validation errors.

- **BEAST Attack (TLS 1.0):** BEAST (Browser Exploit Against SSL/TLS) exploits a chosen-plaintext vulnerability
in TLS 1.0's CBC mode implementation. Attackers with network access can recover
plaintext from TLS 1.0 connections using this attack.

- **DROWN Attack (SSLv2):** DROWN (Decrypting RSA with Obsolete and Weakened eNcryption) allows attackers who
can make connections to a server supporting SSLv2 to decrypt TLS connections to that
server even from clients that don't use SSLv2, due to shared keys.

- **Protocol Downgrade via Version Negotiation:** Enabling old protocol versions allows downgrade attacks where an attacker forces
both client and server to negotiate an older, weaker protocol version even though
both support TLS 1.3, enabling the older protocol's vulnerabilities.


## FAQ

**Q: Are SSLv2 and SSLv3 constants even available in modern Python?**

ssl.PROTOCOL_SSLv2 was removed in Python 3.7 and ssl.PROTOCOL_SSLv3 in Python 3.10
as these protocols are completely insecure. Using these constants will raise an error.
ssl.PROTOCOL_TLSv1 and ssl.PROTOCOL_TLSv1_1 were deprecated in Python 3.10 and
removed in Python 3.12. Code using these constants needs to be updated to
PROTOCOL_TLS_CLIENT or PROTOCOL_TLS_SERVER.


**Q: What is the minimum recommended TLS version in 2025?**

TLS 1.2 is the current minimum for compliance with PCI DSS and NIST guidance. TLS 1.3
is strongly recommended for new systems as it has a simpler, more secure handshake,
removes all cipher suites with known weaknesses, and provides forward secrecy by
default. Configure minimum_version = ssl.TLSVersion.TLSv1_2 at minimum.


**Q: What is ssl.PROTOCOL_TLS vs ssl.PROTOCOL_TLS_CLIENT?**

ssl.PROTOCOL_TLS is deprecated as of Python 3.10. ssl.PROTOCOL_TLS_CLIENT is the
recommended replacement for client contexts and automatically enables certificate
verification (check_hostname=True, verify_mode=CERT_REQUIRED). ssl.PROTOCOL_TLS_SERVER
is for server contexts. Always use the CLIENT/SERVER variants.


**Q: How do I enforce TLS 1.3 only?**

Set ctx.minimum_version = ssl.TLSVersion.TLSv1_3 and ctx.maximum_version = ssl.TLSVersion.TLSv1_3
on the SSL context. Note that this may prevent connections with older clients or servers
that don't support TLS 1.3. For compatibility, use TLSv1_2 as minimum and allow TLS 1.3
negotiation.


**Q: Does this rule check for weak cipher suites as well?**

This rule specifically checks for deprecated protocol version constants. Weak cipher
suite configuration (RC4, DES, export ciphers, NULL ciphers) is a related concern
that requires additional review of the cipher string passed to ctx.set_ciphers().


**Q: What happens when a client connects to a server that only supports TLS 1.0?**

With TLS 1.2+ enforced on the client, the TLS handshake will fail with a protocol
version error. The correct response is to update the server to support TLS 1.2 or
higher, not to lower the client's minimum version. If the legacy server cannot be
updated, document the risk, isolate the connection, and plan migration.


## References

- [CWE-326: Inadequate Encryption Strength](https://cwe.mitre.org/data/definitions/326.html)
- [Python docs: ssl module TLS version constants](https://docs.python.org/3/library/ssl.html#ssl.TLSVersion)
- [OWASP TLS Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html)
- [NIST SP 800-52 Revision 2 - Guidelines for TLS Implementations](https://csrc.nist.gov/publications/detail/sp/800-52/rev-2/final)
- [POODLE Attack Research](https://www.openssl.org/~bodo/ssl-poodle.pdf)

---

Source: https://codepathfinder.dev/registry/python/lang/PYTHON-LANG-SEC-051
Code Pathfinder — Open source, type-aware SAST with cross-file dataflow analysis
