SSL/TLS Security Testing: Vulnerabilities, Configuration Weaknesses, and Testing Techniques

A surprising number of production applications still have SSL/TLS misconfigurations that a basic scan would catch. Expired certificates, support for deprecated protocol versions, weak cipher suites, missing HSTS — these aren't exotic vulnerabilities. They're configuration failures that automated tools have been detecting for a decade. Yet they persist, partly because TLS configuration sits at the infrastructure layer where developers don't always look, and partly because the attack surface is more nuanced than it appears.

This guide covers TLS security testing from the perspective of an application security tester: what to check, why it matters, and the practical tools to find each class of weakness.

Why TLS Configuration Still Matters

TLS has a reputation for being "solved." You get a certificate from Let's Encrypt, your web server handles the handshake, and you move on. In reality, TLS configuration involves dozens of decisions — supported protocol versions, cipher suite preferences, certificate chain validity, HSTS policy, renegotiation handling — each of which has its own failure mode.

The consequences of misconfiguration range from compliance failures (PCI DSS prohibits TLS 1.0 and SSL 3.0) to active exploitation. A server that accepts SSLv3 is vulnerable to POODLE. One that supports RC4 cipher suites is vulnerable to statistical attacks that break the encryption. A server that allows TLS renegotiation without authentication controls is vulnerable to the 2009 renegotiation attack (CVE-2009-3555).

For applications handling authentication tokens, payment data, or sensitive user information, a weak TLS configuration directly undermines every other security control you've built.

The Testing Toolkit

Before diving into specific vulnerabilities, the primary tool for TLS testing is testssl.sh — an open-source shell script that tests a server's TLS configuration comprehensively. It checks protocol support, cipher suites, certificate validity, known vulnerabilities, and more.

# Run a full TLS assessment against a target
testssl.sh https://target.example.com

# Check only specific vulnerabilities
testssl.sh --poodle --beast --heartbleed --ticketbleed --drown https://target.example.com

# Output to JSON for pipeline integration
testssl.sh --jsonfile results.json https://target.example.com

# Test a non-HTTPS service (STARTTLS)
testssl.sh --starttls smtp smtp.target.com:25

For lighter checks, nmap with the ssl-enum-ciphers script enumerates supported cipher suites and grades them:

nmap --script ssl-enum-ciphers -p 443 target.example.com

OpenSSL itself is useful for manual verification:

# Test specific protocol version support
openssl s_client -connect target.example.com:443 -ssl3    # should fail on modern servers
openssl s_client -connect target.example.com:443 -tls1    # TLS 1.0 — should be disabled
openssl s_client -connect target.example.com:443 -tls1_1  # TLS 1.1 — should be disabled

# View the full certificate chain
openssl s_client -connect target.example.com:443 -showcerts

# Test with specific cipher
openssl s_client -connect target.example.com:443 -cipher RC4-SHA

1. Deprecated Protocol Versions

The clearest TLS misconfiguration is supporting protocol versions that should be retired. The current baseline is TLS 1.2, with TLS 1.3 preferred. Anything below TLS 1.2 is deprecated and should be disabled.

Protocol Status Primary Vulnerability
SSL 2.0 Critically deprecated DROWN, broken by design
SSL 3.0 Critically deprecated POODLE (CBC padding oracle)
TLS 1.0 Deprecated (PCI DSS) BEAST, POODLE-TLS, CRIME
TLS 1.1 Deprecated No modern cipher suite support
TLS 1.2 Acceptable Depends on cipher suite selection
TLS 1.3 Recommended Mitigates most prior attacks

Testing is straightforward — try to connect with each protocol version and see if the server accepts it. Most modern web servers (nginx, Apache, IIS) disable TLS 1.0/1.1 by default in recent versions, but legacy applications and load balancers often still enable them for backward compatibility.

2. Weak Cipher Suites

Protocol version is necessary but not sufficient. A TLS 1.2 connection using RC4 or DES cipher suites is still weak. The cipher suite controls the encryption algorithm, key exchange method, and MAC function for the session.

Suites to flag as weak:

Suites that indicate good configuration:

Forward secrecy (via ECDHE or DHE) deserves special attention. Without it, a server's private key compromise retroactively decrypts all previously captured traffic. With forward secrecy, each session uses a unique ephemeral key, so past sessions remain protected even if the long-term key is later compromised.

3. Certificate Validation Issues

Certificate problems are among the most common TLS findings. They range from trivial (expired certificate) to critical (invalid chain, wrong hostname).

Expired and expiring certificates

An expired certificate causes browsers to show hard-stop warnings and breaks automated HTTPS clients. More importantly, it signals a gap in certificate lifecycle management — the same process failure that leads to missed renewals can lead to other security gaps.

# Check certificate expiry manually
echo | openssl s_client -connect target.example.com:443 2>/dev/null | openssl x509 -noout -dates

# Check remaining validity in days
echo | openssl s_client -connect target.example.com:443 2>/dev/null \
  | openssl x509 -noout -enddate \
  | awk -F= '{print $2}' \
  | xargs -I{} date -d '{}' +%s \
  | xargs -I{} sh -c 'echo $(( ({} - $(date +%s)) / 86400 )) days remaining'

Hostname mismatch

The certificate's Common Name (CN) or Subject Alternative Names (SANs) must match the hostname being connected to. A mismatch means the certificate was issued for a different domain, or was not updated when the domain changed. This prevents clients from verifying they're talking to the right server.

# View SANs
echo | openssl s_client -connect target.example.com:443 2>/dev/null \
  | openssl x509 -noout -text \
  | grep -A1 "Subject Alternative Name"

Self-signed certificates in production

Self-signed certificates aren't validated by any trusted CA. Browsers and HTTP clients will reject them (or require explicit override). In production environments, a self-signed cert typically means the application wasn't fully configured before going live — it's a signal worth investigating further.

Incomplete certificate chain

The server should send the full certificate chain — end-entity cert plus all intermediate CAs. When intermediates are missing, some clients (especially mobile and IoT) can't complete validation. Use testssl.sh or SSL Labs' server test to verify chain completeness.

Certificate Transparency (CT) gaps

Modern browsers expect certificates to be logged in Certificate Transparency logs. Certificates not included in CT logs may be flagged by browsers or security monitoring. Check that your CA logs certificates automatically, and use CT log search (crt.sh) to audit what's been issued for your domains — unexpected certificates can indicate shadow IT or compromise.

# Search for all certificates issued for a domain via crt.sh
curl -s "https://crt.sh/?q=%.example.com&output=json" | jq '.[].name_value' | sort -u

4. Known Protocol Vulnerabilities

BEAST (Browser Exploit Against SSL/TLS)

BEAST targets TLS 1.0 and SSL 3.0 using a CBC cipher mode attack. An attacker with a MITM position and the ability to inject predictable plaintext can recover the session cookie. The practical fix is disabling TLS 1.0 entirely, which modern servers do. TLS 1.2 with non-CBC cipher suites (like AES-GCM) is not affected.

testssl.sh --beast https://target.example.com

POODLE (Padding Oracle On Downgraded Legacy Encryption)

POODLE attacks SSL 3.0's CBC padding — the padding is not verified, creating a padding oracle that can be used to decrypt individual bytes. The original POODLE required downgrading to SSL 3.0. POODLE-TLS extended the attack to TLS implementations with the same padding flaw. Fix: disable SSL 3.0 (universal) and ensure TLS implementations check padding correctly.

DROWN (Decrypting RSA with Obsolete and Weakened eNcryption)

DROWN affects servers that share an RSA key pair with any server still supporting SSLv2. Even if your primary server has SSLv2 disabled, if any other service (SMTP, IMAP, old load balancer) using the same private key accepts SSLv2 connections, an attacker can use DROWN to decrypt TLS 1.2 sessions. The fix is ensuring the private key is not used anywhere SSLv2 is enabled.

Heartbleed (CVE-2014-0160)

Heartbleed is a buffer over-read in OpenSSL's heartbeat extension. It allows reading up to 64KB of server memory per request — potentially exposing private keys, session tokens, and other sensitive data from adjacent memory. Despite being discovered in 2014, some legacy systems remain unpatched. Test for it explicitly on any older infrastructure.

testssl.sh --heartbleed https://target.example.com
# Or with nmap:
nmap --script ssl-heartbleed -p 443 target.example.com

CRIME and BREACH

CRIME exploits TLS-level compression (disabled by default in modern TLS implementations). BREACH exploits HTTP-level compression (still common) combined with chosen-plaintext to recover session tokens or CSRF tokens. BREACH is harder to fully mitigate — options include disabling HTTP compression for sensitive responses, randomizing CSRF tokens per response, or using the SameSite cookie attribute to reduce CSRF surface.

ROBOT (Return Of Bleichenbacher's Oracle Threat)

ROBOT is a 2017 resurrection of Bleichenbacher's 1998 attack on PKCS#1 v1.5 RSA padding. Servers with the vulnerability allow an attacker to perform RSA decryption and signing operations using the server's private key. The fix is disabling RSA key exchange cipher suites entirely (which forward secrecy requires anyway).

5. HSTS and Downgrade Attacks

HTTP Strict Transport Security (HSTS) tells browsers to only ever connect to a domain over HTTPS, for a specified duration. Without HSTS, a user who navigates to http://target.com (without HTTPS) is vulnerable to SSL stripping — an attacker downgrades the connection to HTTP before it reaches HTTPS.

Test for HSTS presence and correctness:

# Check for HSTS header
curl -sI https://target.example.com | grep -i strict-transport-security

# Expected response:
# Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Common HSTS problems to flag:

The HSTS preload list (hstspreload.org) hardcodes domains into browsers so the first visit is also protected. Submitting to the preload list requires max-age=31536000; includeSubDomains; preload and ensuring all subdomains are HTTPS-ready — a commitment you can't easily undo.

6. Certificate Pinning

Certificate pinning associates a specific certificate or public key with a host, rejecting any certificate that doesn't match — even a valid CA-signed one. It protects against rogue CA issuance or CA compromise.

HTTP Public Key Pinning (HPKP) was the browser-based mechanism, but it's been deprecated and removed from major browsers due to misconfiguration risks (a misconfigured pin could permanently break access to a site). The modern alternatives are:

For testing mobile apps and API clients, certificate pinning bypass is often required to intercept HTTPS traffic. Common bypass techniques include using a custom CA on rooted devices, frida-based hooking to override pinning logic, or patching the APK/IPA to remove the pinning check.

7. TLS for Non-Web Services

TLS testing often focuses on HTTPS, but the same configuration issues appear on other protocols that use STARTTLS or TLS natively:

# SMTP with STARTTLS
testssl.sh --starttls smtp smtp.target.example.com:25

# IMAP with STARTTLS
testssl.sh --starttls imap mail.target.example.com:143

# LDAP with STARTTLS (LDAPS on 636)
testssl.sh --starttls ldap ldap.target.example.com:389

# PostgreSQL with TLS
testssl.sh --starttls postgres db.target.example.com:5432

STARTTLS stripping is an attack specific to STARTTLS protocols: an active MITM can suppress the STARTTLS capability advertisement, causing the client to fall back to plaintext. SMTP is particularly vulnerable because RFC 3207 allows unauthenticated STARTTLS upgrades. Services that handle authentication or sensitive data over these protocols should use TLS natively (SMTPS, IMAPS, LDAPS) rather than STARTTLS where possible.

8. Automated TLS Testing in CI/CD

TLS configuration should be continuously monitored, not just tested once. Certificates expire, server configurations drift after updates, and new vulnerabilities emerge. Integrate TLS testing into your pipeline:

# Basic testssl.sh CI check — fails if severity is HIGH or CRITICAL
testssl.sh --severity HIGH --quiet --exit-code 5 https://target.example.com
# Exit code 5 = vulnerability of specified severity found

# Check certificate expiry with alerting threshold
DAYS_UNTIL_EXPIRY=$(echo | openssl s_client -connect target.example.com:443 2>/dev/null \
  | openssl x509 -noout -enddate \
  | cut -d= -f2 \
  | xargs -I{} date -d '{}' +%s \
  | xargs -I{} sh -c 'echo $(( ({} - $(date +%s)) / 86400 ))')

if [ "$DAYS_UNTIL_EXPIRY" -lt 30 ]; then
  echo "WARNING: Certificate expires in $DAYS_UNTIL_EXPIRY days"
  exit 1
fi

For certificate lifecycle management, modern certificate management tools (cert-manager in Kubernetes, AWS ACM, Let's Encrypt with auto-renewal) reduce manual certificate handling. But they don't eliminate the need for monitoring — renewal automation can fail silently.

TLS Testing Checklist

Before closing a TLS assessment, verify:

Ironimo runs automated TLS assessments as part of every web application scan — checking protocol versions, cipher suites, certificate validity, and known vulnerabilities across your entire attack surface. Continuous monitoring catches configuration drift before your next audit does.

Start free scan
← Back to Blog