Skip to content

VNX-GO-041: Use of deprecated TLS version

Detect Go TLS configuration that sets MinVersion or MaxVersion (or an options field such as TLSMinVersion) to SSL 3.0, TLS 1.0 or TLS 1.1 (by constant, raw protocol number, a local variable or a package-level constant holding one, a Traefik-style string option or an Envoy TlsParameters enum), enabling negotiation of deprecated protocol versions.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-GO-041
Severity High
SARIF level error
Kind sast
Languages Go
CWE CWE-326
CAPEC CAPEC-63
ATT&CK T1068.003
CWSS vector CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H
Tags tls crypto version
Source internal/sast/rules/vnx-go-041.rego

Overview

This rule flags tls.Config struct literals or assignments where MinVersion or MaxVersion is set to tls.VersionSSL30, tls.VersionTLS10 or tls.VersionTLS11 (under any import alias, optionally wrapped in uint16()), to the raw protocol numbers 0x0300 to 0x0302 (only in a file that imports a TLS package), to a local variable assigned one of those values a few lines above, or to a package-level const/var declared as one. An options-struct field named like TLSMinVersion or MinTLSVersion set to one of the constants is reported too, as is a string-typed option set to the constant’s name (Traefik’s MinVersion: "VersionTLS10") and an Envoy go-control-plane TlsMinimumProtocolVersion or TlsMaximumProtocolVersion set to TlsParameters_TLSv1_0 or TlsParameters_TLSv1_1. Comparisons such as state.Version == tls.VersionTLS10, switch cases, version-name maps, comments, string literals (including multi-line code-generation templates) and _test.go files are not reported, and a version read from configuration at runtime or passed as a function argument is not followed. Both TLS 1.0 and TLS 1.1 have been formally deprecated by the IETF (RFC 8996, March 2021) and are prohibited by PCI-DSS since June 2018. Allowing these versions permits negotiation of ciphersuites and protocol features that are vulnerable to POODLE, BEAST, CRIME, and other well-documented attacks. This maps to CWE-326: Inadequate Encryption Strength.

Go’s crypto/tls package defaults to tls.VersionTLS12 as MinVersion since Go 1.18, but explicitly setting the minimum to an older version overrides this safe default and creates a regression that may go unnoticed in code review.

Why This Matters

TLS 1.0 and TLS 1.1 rely on cipher constructions and negotiation mechanisms that are no longer considered safe. BEAST (Browser Exploit Against SSL/TLS) exploits a CBC-mode IV predictability issue in TLS 1.0 that allows session cookie decryption. POODLE (Padding Oracle On Downgraded Legacy Encryption) attacks SSLv3 but a variant affects TLS 1.0’s CBC ciphersuites. Both attacks require an active network position (man-in-the-middle or on the same network segment), but coffee-shop Wi-Fi and cloud shared-tenancy environments make this a realistic threat model for web applications.

Beyond direct cryptographic attacks, TLS 1.0 and 1.1 lack support for secure cipher suites available in TLS 1.2 (AEAD ciphers such as AES-GCM and ChaCha20-Poly1305) and TLS 1.3 (which eliminates all non-AEAD options entirely). PCI-DSS 3.2 made TLS 1.2 the minimum mandatory version for all payment processing environments. Major browsers (Chrome, Firefox, Safari, Edge) have removed support for TLS 1.0 and 1.1. Continuing to allow these versions primarily serves legacy clients that represent a negligible fraction of modern traffic while materially increasing risk. MITRE ATT&CK T1068.003 covers exploitation of weakened cryptographic configurations.

What Gets Flagged

The rule fires on tls.Config fields that reference deprecated version constants.

// FLAGGED: MinVersion allows TLS 1.0, BEAST and POODLE variant attacks possible
func createTLSConfig() *tls.Config {
    return &tls.Config{
        MinVersion: tls.VersionTLS10, // deprecated, RFC 8996
    }
}

// FLAGGED: explicit TLS 1.1 minimum
func serverConfig() *tls.Config {
    cfg := &tls.Config{}
    cfg.MinVersion = tls.VersionTLS11
    return cfg
}

// FLAGGED: MaxVersion capped at TLS 1.1 prevents TLS 1.2/1.3 negotiation
func legacyClientConfig() *tls.Config {
    return &tls.Config{
        MaxVersion: tls.VersionTLS11,
    }
}

// FLAGGED: the weak value travels through a local variable
func listen(addr string) (net.Listener, error) {
    minVer := uint16(tls.VersionTLS10)
    conf := &tls.Config{MinVersion: minVer}
    return tls.Listen("tcp", addr, conf)
}
// SAFE: TLS 1.2 minimum with preferred TLS 1.3
func createTLSConfig(certFile, keyFile string) (*tls.Config, error) {
    cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    if err != nil {
        return nil, err
    }
    return &tls.Config{
        MinVersion:   tls.VersionTLS12, // RFC 8996 compliant minimum
        Certificates: []tls.Certificate{cert},
        CipherSuites: []uint16{
            tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
            tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
        },
    }, nil
}

Remediation

  1. Set MinVersion: tls.VersionTLS12 in all tls.Config structs for both servers and clients. This is already the Go default since 1.18, but any explicit MinVersion assignment must be updated to avoid overriding the safe default.

    // SAFE: explicit TLS 1.2 minimum, TLS 1.3 preferred automatically
    func newTLSConfig() *tls.Config {
        return &tls.Config{
            MinVersion: tls.VersionTLS12,
            // Go's crypto/tls negotiates TLS 1.3 automatically when both
            // sides support it, no explicit MaxVersion needed.
        }
    }
  2. Prefer TLS 1.3 only (MinVersion: tls.VersionTLS13) for internal services and APIs where all clients are under your control. TLS 1.3 eliminates weak cipher suites entirely, mandates forward secrecy, and reduces handshake round-trips.

    // SAFE: TLS 1.3 only for internal microservice communication
    func internalServiceTLSConfig() *tls.Config {
        return &tls.Config{
            MinVersion: tls.VersionTLS13,
        }
    }
  3. Audit all http.Server, http.Transport, grpc.ServerOption, and net.Listener usages to ensure no tls.Config is instantiated without an explicit MinVersion or with a deprecated version constant. Centralise TLS configuration in a shared package to enforce consistent settings.

  4. Test TLS configuration with go test using crypto/tls test helpers, or with external tools such as testssl.sh or Qualys SSL Labs, to verify that TLS 1.0 and 1.1 are not negotiated in production.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-go-041
// nosec vnx-go-041

Or record an ignore rule: vulnetix ignore add --rule vnx-go-041 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-go-041.rego, cli/internal/sast/docs/vnx-go-041.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.