HIGH broken authenticationmutual tls

Broken Authentication with Mutual Tls

How Broken Authentication Manifests in Mutual Tls

Mutual TLS (mTLS) authentication failures often stem from improper certificate validation, misconfigured trust chains, or incomplete certificate lifecycle management. In mTLS implementations, broken authentication typically manifests through several specific attack vectors.

One common pattern involves certificate pinning bypass. When applications hardcode certificate fingerprints or public keys without proper validation, attackers can exploit certificate rotation or introduce rogue certificates that still match the pinned value. For example, a Node.js server might validate certificates using:

const tls = require('tls');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),
  requestCert: true,
  rejectUnauthorized: true,
  ca: [fs.readFileSync('ca-cert.pem')],
  checkServerIdentity: (host, cert) => {
    // Broken: only checking CN, not SAN
    if (cert.subject.CN !== host) {
      throw new Error('Certificate subject mismatch');
    }
  }
};

const server = tls.createServer(options, (socket) => {
  // Authentication complete
});

This implementation is vulnerable because it only checks the Common Name (CN) field while ignoring Subject Alternative Names (SAN), allowing certificate spoofing for alternate hostnames.

Another mTLS-specific authentication break occurs through improper certificate revocation checking. Many implementations skip CRL (Certificate Revocation List) or OCSP (Online Certificate Status Protocol) validation for performance reasons, creating windows where revoked certificates remain valid. The vulnerability manifests when:

const https = require('https');

const agent = new https.Agent({
  rejectUnauthorized: true,
  // Missing: checkServerIdentity for mutual auth
  // Missing: certificate revocation checking
});

https.request({
  hostname: 'api.example.com',
  port: 443,
  path: '/resource',
  method: 'GET',
  agent: agent
}, (res) => {
  // Process response
});

Without explicit revocation checks, compromised certificates remain usable until expiration.

Certificate chain validation bypasses represent another mTLS-specific authentication break. Applications may accept certificates with weak intermediate CA signatures or missing intermediate certificates in the chain. This allows attackers to present self-signed certificates that superficially appear valid:

function validateCertificateChain(cert) {
  // Broken: not validating intermediate CA
  if (cert.issuer === 'CN=MyCompany CA') {
    return true;
  }
  return false;
}

// Attacker can forge: Issuer: CN=MyCompany CA, but self-signed

Time-based certificate validation failures also create authentication breaks. Applications that don't properly handle clock skew or use weak time comparisons may accept expired or not-yet-valid certificates:

function isCertificateValid(cert) {
  const now = Date.now();
  // Vulnerable to timing attacks and clock skew
  return now >= cert.notBefore && now <= cert.notAfter;
}

// Attacker with clock manipulation or during certificate rollover windows

Mutual Tls-Specific Detection

Detecting broken authentication in mTLS requires testing certificate validation logic, trust chain integrity, and authentication completeness. Automated scanning tools like middleBrick can identify these specific mTLS vulnerabilities through black-box testing.

middleBrick's mTLS detection capabilities include:

Detection Type Test Method Indicator
Certificate Validation Bypass Present expired/invalid certificates Server accepts without rejection
Trust Chain Verification Supply self-signed intermediate certificates Missing intermediate CA rejection
Revocation Checking Present revoked certificates No revocation status validation
Certificate Pinning Bypass Rotate certificates with same fingerprint Pinning doesn't validate full chain

Manual detection techniques include using OpenSSL to test certificate validation:

# Test with expired certificate
openssl s_client -connect api.example.com:443 \
  -cert expired-cert.pem \
  -key expired-key.pem \
  -CAfile ca-cert.pem

# Test with self-signed intermediate
openssl s_client -connect api.example.com:443 \
  -cert client-cert.pem \
  -key client-key.pem \
  -CAfile self-signed-ca.pem

# Test revocation status
openssl s_client -connect api.example.com:443 \
  -cert revoked-cert.pem \
  -key revoked-key.pem \
  -CAfile ca-cert.pem

Network-level detection using Wireshark or tcpdump can reveal authentication bypasses:

# Capture mTLS handshake and certificate exchange
tcpdump -i eth0 -w mtls-capture.pcap port 443

# Analyze certificate details
openssl x509 -in captured-cert.pem -text -noout

# Check for missing revocation information
openssl verify -verbose -CAfile ca-cert.pem client-cert.pem

middleBrick specifically tests mTLS endpoints by attempting connections with:

  • Expired certificates
  • Certificates with invalid signatures
  • Missing intermediate CA certificates
  • Revoked certificates (if CRL/OCSP endpoints are accessible)
  • Certificates with mismatched hostnames

The scanner reports authentication failures with severity levels based on the security impact and likelihood of exploitation.

Mutual Tls-Specific Remediation

Effective mTLS authentication remediation requires implementing comprehensive certificate validation, proper trust chain verification, and robust certificate lifecycle management. Here are specific code-level fixes for mTLS authentication breaks.

Complete certificate chain validation using Node.js:

const tls = require('tls');
const fs = require('fs');

function createSecureMTLSContext() {
  const caCerts = fs.readFileSync('ca-bundle.pem');
  
  return {
    key: fs.readFileSync('server-key.pem'),
    cert: fs.readFileSync('server-cert.pem'),
    requestCert: true,
    rejectUnauthorized: true,
    ca: [caCerts],
    checkServerIdentity: (host, cert) => {
      // Complete validation: check SAN and CN
      const subjectAltNames = cert.subjectaltname || '';
      const validHosts = subjectAltNames
        .split(',')
        .map(s => s.trim())
        .filter(s => s.startsWith('DNS:'))
        .map(s => s.substring(4));
      
      validHosts.push(cert.subject.CN);
      
      if (!validHosts.includes(host)) {
        throw new Error(`Certificate not valid for ${host}`);
      }
    },
    secureOptions: require('constants').SSL_OP_NO_TLSv1 | require('constants').SSL_OP_NO_TLSv1_1,
    honorCipherOrder: true,
    minVersion: 'TLSv1.2'
  };
}

const server = tls.createServer(createSecureMTLSContext(), (socket) => {
  // Authentication complete - certificate is valid
  const cert = socket.getPeerCertificate();
  console.log('Authenticated client:', cert.subject.CN);
});

Certificate revocation checking implementation:

const { X509Certificate } = require('crypto');
const axios = require('axios');

async function checkCertificateRevocation(certPem) {
  const cert = X509Certificate.fromPEM(certPem);
  
  // Check certificate validity period
  const now = Date.now();
  if (now < cert.validFrom || now > cert.validTo) {
    throw new Error('Certificate expired or not yet valid');
  }
  
  // Check for revocation information in certificate
  const ext = cert.extensions.find(e => e.name === 'crlDistributionPoints');
  if (ext) {
    const crlUrls = ext.critical ? ext.value : ext.value.split(',').map(s => s.trim());
    for (const url of crlUrls) {
      try {
        const crlResponse = await axios.get(url, { timeout: 5000 });
        const crl = parseCRL(crlResponse.data); // Implement CRL parsing
        if (crl.isRevoked(cert.serialNumber)) {
          throw new Error('Certificate revoked');
        }
      } catch (e) {
        console.warn('CRL check failed:', e.message);
      }
    }
  }
  
  return true;
}

Certificate pinning with full chain validation:

const crypto = require('crypto');

class MTLSVerifier {
  constructor(trustedCAs, pinnedPublicKeys) {
    this.trustedCAs = trustedCAs;
    this.pinnedPublicKeys = pinnedPublicKeys;
  }
  
  verifyCertificateChain(certChain) {
    // Validate trust chain
    const trusted = this.validateTrustChain(certChain);
    if (!trusted) {
      throw new Error('Untrusted certificate chain');
    }
    
    // Validate pinning
    const leafCert = certChain[0];
    const leafPublicKey = leafCert.publicKey.toString('base64');
    
    if (!this.pinnedPublicKeys.includes(leafPublicKey)) {
      throw new Error('Certificate pinning mismatch');
    }
    
    return true;
  }
  
  validateTrustChain(chain) {
    // Implement proper chain validation
    // Check signatures, expiration, revocation
    return true;
  }
}

Time-based validation with clock skew tolerance:

function isCertificateValidWithSkew(cert, clockSkewMinutes = 5) {
  const now = Date.now();
  const skewMs = clockSkewMinutes * 60 * 1000;
  
  return now + skewMs >= cert.notBefore && 
         now - skewMs <= cert.notAfter;
}

// Usage in TLS context
const options = {
  ...,
  checkServerIdentity: (host, cert) => {
    if (!isCertificateValidWithSkew(cert)) {
      throw new Error('Certificate timing invalid');
    }
    // Additional validation...
  }
};

These remediation techniques address the most common mTLS authentication breaks by ensuring complete certificate validation, proper trust chain verification, and robust lifecycle management.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How does middleBrick detect broken authentication in mTLS endpoints?
middleBrick tests mTLS endpoints by attempting connections with expired certificates, self-signed intermediates, revoked certificates, and mismatched hostnames. It verifies whether the server properly rejects invalid certificates and validates the complete trust chain. The scanner reports authentication failures with severity levels based on the security impact and provides specific remediation guidance for each finding.
What's the difference between mTLS authentication breaks and regular TLS authentication breaks?
mTLS authentication breaks are more complex because they involve validating both client and server certificates. Common mTLS-specific issues include improper intermediate CA validation, missing revocation checking, certificate pinning bypass through chain manipulation, and incomplete hostname validation across SAN fields. Regular TLS breaks typically involve server certificate validation only, while mTLS requires comprehensive bidirectional certificate validation.