Skip to content

CWE-757: Selection of Less-Secure Algorithm During Negotiation ('Algorithm Downgrade')

Overview

Some protocols let two parties negotiate which algorithm to use for a protection mechanism such as encryption, authentication, or key exchange - a TLS handshake choosing a cipher suite, or an SSH connection choosing a key-exchange algorithm. This weakness occurs when the negotiation does not enforce the strongest algorithm both sides actually support. An attacker who can influence the negotiation, usually by sitting on the network path, forces the connection down to a weaker algorithm or to no protection at all, without ever having to break the strong algorithm directly.

Relationship to Other CWEs

CWE-757 is a child of the CWE-693 (Protection Mechanism Failure) pillar, specific to negotiated protocols. It is distinct from CWE-327 (Use of a Broken or Risky Cryptographic Algorithm), which covers code that chooses a weak algorithm directly with no negotiation involved; CWE-757 covers a negotiation that fails to stop an attacker steering the outcome to a weaker option. A finding that names a specific broken algorithm hardcoded in application code (MD5, DES, RC4) usually belongs on the CWE-327 page; a finding about protocol or cipher-suite downgrade, fallback, or negotiation behavior belongs here.

OWASP Classification

A04:2025 - Cryptographic Failures

Risk

High: A successful downgrade attack forces a connection onto weak or no encryption, so an attacker on the network path can read or tamper with traffic instead of having to defeat strong cryptography directly. POODLE (SSLv3 fallback) and FREAK and Logjam (forced export-grade RSA/DHE) are real-world examples. DROWN is the neighbouring case rather than an example of this weakness: it leaves the victim's connection alone and uses a separate SSLv2 server sharing the same RSA key as an oracle to decrypt recorded TLS sessions, so what it punishes is keeping the obsolete protocol reachable at all rather than any downgrade of the connection in front of you.

Remediation Steps

Core Principle: Negotiation must never settle on an algorithm weaker than the strongest one both parties support, and the way to guarantee that is to remove weak algorithms from the negotiable set entirely rather than merely preferring strong ones.

Trace the Data Path

  • Source: The negotiation message itself - a TLS ClientHello's offered cipher suites, an SSH key-exchange algorithm list, or any capability-advertisement step in a handshake. An on-path attacker can rewrite it before it reaches the server.
  • Sink: The selection logic that picks which algorithm to use for the rest of the session.
  • Data Flow / Missing Controls: Look for negotiation logic that accepts whatever the peer offers without an enforced floor, protocol and cipher configuration that still lists deprecated options as available even if not preferred, and missing integrity protection over the negotiation transcript, which is what lets an attacker rewrite the offered list unnoticed.

Disable Weak Algorithms Entirely (Primary Defense)

Do not rely on "prefer the strongest, but still accept weaker" ordering - if a weak option remains in the accepted set, an attacker who can manipulate the negotiation can still select it. Instead:

  • Remove deprecated protocol versions and cipher suites from the server and client configuration outright: no SSLv2/SSLv3/TLS 1.0/TLS 1.1, no NULL/export/anonymous ciphers, no RC4, no static (non-ephemeral) key exchange.
  • Configure an explicit minimum protocol version (TLS 1.2, prefer TLS 1.3) and an explicit allowlist of approved cipher suites, not a blocklist of disallowed ones.
  • Apply the same principle to any other negotiated protocol in use, not just TLS: SSH key-exchange and cipher algorithms, application-level protocol negotiation.

Protect the Negotiation Itself (Defense in Depth)

  • Use protocols and library versions that authenticate the negotiation transcript so a rewritten offer list is detected and the connection aborted (TLS 1.3's downgrade-protection bytes, TLS_FALLBACK_SCSV for TLS 1.2 and earlier, SSH's exchange-hash signature covering the algorithm lists).
  • Do not implement custom protocol-version fallback logic that silently retries with a weaker protocol on failure - this is how POODLE reached SSLv3. The flaw it then exploited was SSLv3's CBC padding, which the fallback is what delivered connections to.

Test the Fix

  • Scan the endpoint with a TLS configuration scanner (testssl.sh, SSL Labs, or nmap --script ssl-enum-ciphers) and confirm only the approved protocol versions and cipher suites are offered.
  • Attempt to force a downgraded connection with a tool that only offers weak/legacy options and confirm the server refuses to negotiate rather than falling back.
  • Confirm downgrade-detection is active where supported (TLS 1.3 downgrade sentinel, TLS_FALLBACK_SCSV) and re-scan after any configuration change.

Common Vulnerable Patterns

// VULNERABLE - pseudo-code
// negotiation accepts whatever the peer proposes, including weak options
offered_algorithms = peer.propose_algorithms()   // attacker on-path can rewrite this list
selected = pick_first_mutually_supported(offered_algorithms, server_supported_algorithms)
// server_supported_algorithms still includes RC4, SSLv3, export-grade DHE
begin_session(selected)

Why this is vulnerable: the peer's proposal is attacker-controlled whenever anyone sits on the path, and the server's own list is what decides the floor. Keeping RC4 and SSLv3 in server_supported_algorithms means the server has already agreed to use them if asked - so an on-path attacker does not need to break anything, only to rewrite the proposal so that the weakest mutually supported option is the only mutually supported option.

Secure Patterns

// SECURE - pseudo-code
APPROVED_ALGORITHMS = {"TLS1.3-AES256-GCM", "TLS1.3-CHACHA20", "TLS1.2-ECDHE-AES256-GCM"}
// no deprecated protocol version, cipher, or key-exchange method is ever in this set

offered_algorithms = peer.propose_algorithms()
selected = pick_strongest_in(offered_algorithms, APPROVED_ALGORITHMS)

if selected is None:
    abort_connection("no mutually supported strong algorithm")

verify_negotiation_transcript_integrity(offered_algorithms, selected)  // detect tampering
begin_session(selected)

Why this works: weak algorithms were never added to the approved set, so there is nothing weak for a manipulated negotiation to select. Verifying the negotiation transcript closes the remaining gap: an attacker who rewrote the offered list is detected and the handshake aborts instead of downgrading silently.

Migration Considerations

Removing deprecated protocol versions and cipher suites can break connectivity for legacy clients that only support them (older mobile OS versions, embedded devices, unmaintained integration partners). Roll changes out in phases: first disable the weakest options (SSLv2/SSLv3, export ciphers, RC4) since almost nothing legitimate still depends on them, monitor connection logs for negotiated protocol/cipher versions to find remaining legacy clients, notify affected integrators with a deprecation timeline, then remove TLS 1.0/1.1 once traffic confirms no dependency remains. Where a legacy peer genuinely cannot move, record the exception with an expiry date rather than leaving the weak option enabled by default.

Additional Resources