Weakness reference
CWE-757

Selection of Less-Secure Algorithm During Negotiation

This weakness occurs when software chooses a weaker encryption algorithm, protocol version, or security mechanism during negotiation, even though stronger…

01Summary

This weakness occurs when software chooses a weaker encryption algorithm, protocol version, or security mechanism during negotiation, even though stronger options are available. An attacker can often force this downgrade by manipulating the negotiation process, leaving the connection vulnerable to attacks that would fail against the stronger algorithm. This is a common vector in TLS/SSL connections, API authentication, and any system where client and server agree on a security method.

02How It Happens

During protocol negotiation, client and software typically exchange lists of supported algorithms or versions and agree on one to use. If the selection logic prioritizes compatibility over security—or if an attacker can intercept and modify the negotiation—the software may select a deprecated or weak option. This often happens when:

- The software supports legacy algorithms for backward compatibility but doesn't deprioritize them. - Negotiation messages are not authenticated, allowing an attacker to strip strong options from the advertised list. - The code defaults to the weakest common option rather than the strongest. - Error handling falls back to an insecure mode when negotiation fails.

03Real-World Impact

Downgrade attacks can expose encrypted traffic to cryptanalysis. For example, forcing a connection to use an older TLS version or a weak cipher suite may allow an attacker to decrypt previously captured traffic or perform real-time man-in-the-middle attacks. In API authentication, selecting a weaker signing algorithm could allow token forgery. The severity depends on the gap between the weak and strong options—a downgrade from TLS 1.3 to TLS 1.0 is catastrophic; a downgrade from AES-256 to AES-128 is less severe but still undesirable.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import ssl
import socket

def connect_to_server(hostname):
    context = ssl.create_default_context()
    # Explicitly allow older, weaker TLS versions for compatibility
    context.minimum_version = ssl.TLSVersion.TLSv1_0
    context.maximum_version = ssl.TLSVersion.TLSv1_2
    
    with socket.create_connection((hostname, 443)) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            return ssock.getpeername()

Why it's vulnerable:
The code explicitly permits TLS 1.0 and 1.2, both of which have known weaknesses. An attacker can force negotiation down to TLS 1.0, which is vulnerable to BEAST and other attacks.

Fixed pattern
import ssl
import socket

def connect_to_server(hostname):
    context = ssl.create_default_context()
    # Enforce minimum TLS 1.2; prefer 1.3 if available
    context.minimum_version = ssl.TLSVersion.TLSv1_2
    context.maximum_version = ssl.TLSVersion.TLSv1_3
    
    with socket.create_connection((hostname, 443)) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            return ssock.getpeername()
Vulnerable pattern
<?php
$options = array(
    'ssl' => array(
        'protocol' => 'tlsv1.0',  // Explicitly request weak TLS version
        'ciphers' => 'DEFAULT',   // Accept any cipher, including weak ones
    )
);

$context = stream_context_create($options);
$fp = fopen('https://example.com', 'r', false, $context);
$response = stream_get_contents($fp);
fclose($fp);
?>

Why it's vulnerable:
The code hardcodes TLS 1.0 and accepts any cipher suite, including deprecated ones. This removes the ability to negotiate a stronger version even if the server supports it.

Fixed pattern
<?php
$options = array(
    'ssl' => array(
        'min_tls_version' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
        'ciphers' => 'HIGH:!aNULL:!MD5',  // Restrict to strong ciphers
        'verify_peer' => true,
        'verify_peer_name' => true,
    )
);

$context = stream_context_create($options);
$fp = fopen('https://example.com', 'r', false, $context);
$response = stream_get_contents($fp);
fclose($fp);
?>

05Prevention Checklist

Set minimum protocol versions explicitly.
Enforce TLS 1.2 or higher; prefer TLS 1.3 where possible. Do not allow fallback to SSL 3.0, TLS 1.0, or 1.1.
Restrict cipher suites to strong algorithms.
Use allowlists (e.g., HIGH:!aNULL:!MD5) rather than defaults; exclude deprecated ciphers like DES, RC4, and MD5-based signatures.
Authenticate negotiation messages.
Ensure the protocol negotiation itself cannot be tampered with by an attacker (e.g., use ALPN with certificate pinning).
Test with security scanners.
Use tools like testssl.sh or nmap --script ssl-enum-ciphers to verify that weak versions and ciphers are not advertised or accepted.
Monitor and log negotiation choices.
Record which protocol version and cipher suite were selected for each connection; alert on unexpected downgrades.
Disable legacy support at the OS/library level.
If possible, remove or disable support for old TLS versions in the underlying SSL/TLS library rather than relying on application-level filtering.

06Signs You May Already Be Affected

Check your TLS configuration and connection logs for evidence of weak protocol versions or ciphers being used. Tools like openssl s_client can reveal what versions and ciphers your server advertises. If logs show connections using TLS 1.0, 1.1, or weak ciphers (especially those with "export" or "anon" in the name), your system is vulnerable to downgrade attacks. Additionally, if your application accepts user-controlled protocol or cipher selection without validation, review that code immediately.

07Related Recent Vulnerabilities