HIGH missing authenticationmutual tls

Missing Authentication with Mutual Tls

How Missing Authentication Manifests in Mutual TLS

Mutual TLS (mTLS) requires both parties to present a valid certificate during the TLS handshake. When authentication is missing, one side either does not request the peer’s certificate or does not validate it correctly. This creates a classic impersonation vector: an attacker can present a self‑signed or otherwise unauthorized certificate and still complete the handshake.

  • Server‑side missing client authentication – The TLS server is configured with ClientAuth: NoClientCert (Go), requestCert: false (Node.js), or ssl.CERT_NONE (Python). The server will accept any client, even one that presents no certificate or a forged one.
  • Client‑side missing server authentication – The client disables verification (InsecureSkipVerify: true in Go, rejectUnauthorized: false in Node.js, verify_mode = ssl.CERT_NONE in Python). An attacker can terminate the TLS connection with a fraudulent certificate and impersonate the legitimate service.
  • Weak certificate validation logic – Custom VerifyPeerCertificate callbacks that always return nil or ignore the leaf certificate’s signature, allowing any certificate chain to pass.

These misconfigurations appear in code paths that build the TLS configuration before the server starts listening or before a client makes a request. For example, in a Go HTTP server the tls.Config is passed to http.Server.TLSConfig; if the ClientAuth field is not set to tls.RequireAndVerifyClientCert, the server skips client cert validation. In Node.js, the https.createServer options requestCert and rejectUnauthorized control whether the server asks for and validates a client certificate.

Attackers exploit this by:

  • Connecting to the API without presenting a client certificate and still receiving a successful response.
  • Presenting a certificate signed by a CA they control when the server does not verify the certificate chain against a trusted root.
  • Performing a man‑in‑the‑middle attack when the client does not validate the server’s certificate, allowing the attacker to decrypt and modify traffic.

Mutual TLS‑Specific Detection

middleBrick performs unauthenticated black‑box scanning of the API endpoint. For Mutual TLS it focuses on the TLS handshake itself, checking whether the server enforces client certificate authentication and whether the client validates the server’s certificate.

The scanner proceeds as follows:

  1. It initiates a TLS handshake without sending a client certificate. If the server completes the handshake and returns an application‑level response (e.g., HTTP 200), middleBrick flags missing client authentication.
  2. It repeats the handshake with a client certificate that is signed by an untrusted CA. If the server still accepts the connection, it indicates that certificate chain validation is disabled or misconfigured.
  3. From the client perspective, middleBrick attempts to connect to the target using a TLS client that sets InsecureSkipVerify‑equivalent flags. If the connection succeeds despite presenting an invalid or self‑signed server certificate, the scanner reports missing server authentication.
  4. Additionally, middleBrick inspects any exposed configuration endpoints (e.g., /debug/config, /actuator/env) that may reveal TLS settings such as ClientAuth: none or verify: false.

These checks are performed in parallel with the other 11 security scans and are completed within the 5‑15 second window advertised for a full scan.

You can trigger the same detection locally with the middleBrick CLI:

# Install the CLI (npm)
npm i -g middlebrick
# Scan an API endpoint for missing mTLS authentication
middlebrick scan https://api.example.com

In a CI/CD pipeline, the GitHub Action can be used to fail a build when the mTLS‑related findings push the overall score below a threshold:

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
  middlebrick:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run middleBrick scan
        uses: middlebrick/action@v1
        with:
          api-url: https://staging.example.com
          fail-under: "C"   # fail if score drops below C

When using an AI coding assistant, the MCP Server integration lets you scan the same endpoint directly from your IDE:

# In Cursor or Claude IDE
middlebrick scan --url https://dev.example.com

Mutual TLS‑Specific Remediation

Remediation consists of configuring the TLS stack to require and validate certificates on both sides. The exact API differs by language, but the principles are the same:

  • Require the peer to present a certificate.
  • Validate that certificate chain against a trusted root CA.
  • Optionally, verify the certificate’s subject or SAN matches the expected identity.

Below are concrete, syntactically correct examples for the three most common backend languages.

Go (net/http)

package main

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	// Load the CA that issued client certificates
	caCert, err := ioutil.ReadFile("client_ca.pem")
	if err != nil {
		log.Fatalf("failed to read CA: %v", err)
	}
	caPool := x509.NewCertPool()
	caPool.AppendCertsFromPEM(caCert)

	// TLS config that mandates a valid client cert
	tlsConfig := &tls.Config{
		ClientAuth: tls.RequireAndVerifyClientCert,
		ClientCAs:  caPool,
		// Optional: verify the hostname matches the expected SAN
		VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
			// verifiedChains already contains chains validated against ClientCAs
			if len(verifiedChains) == 0 {
				return fmt.Errorf("no valid client certificate chain")
			}
			// Additional checks (e.g., verify OU, SAN) can go here
			return nil
		},
	}

	server := &http.Server{
		Addr:      ":8443",
		TLSConfig: tlsConfig,
		Handler:   http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte("mTLS protected\n"))
		}},
	}

	log.Fatal(server.ListenAndServeTLS("server.pem", "server.key"))
}

Node.js (https)

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

const options = {
  key:  fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.pem'),
  // Require clients to present a certificate
  requestCert: true,
  // Reject if the client cert is not trusted
  rejectUnauthorized: true,
  // Trust only this CA for client certs
  ca: fs.readFileSync('client_ca.pem'),
  // Optional: enforce specific SAN or OU checks
  checkServerIdentity: (host, cert) => {
    // Return undefined if hostname matches, otherwise an error
    return require('tls').checkServerIdentity(host, cert);
  }
};

const server = https.createServer(options, (req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('mTLS protected\n');
});

server.listen(8443, () => {
  console.log('mTLS server listening on port 8443');
});

Python (ssl.SSLContext)

import ssl
import socket

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
# Load server certificate and key
context.load_cert_chain(certfile='server.pem', keyfile='server.key')
# Require client certificates
context.verify_mode = ssl.CERT_REQUIRED
# Load the CA that issued client certs
context.load_verify_locations(cafile='client_ca.pem')
# Optional: hostname verification (default is on for CLIENT_AUTH)

bindsocket = socket.socket()
bindsocket.bind(('0.0.0.0', 8443))
bindsocket.listen(5)

while True:
  newsocket, fromaddr = bindsocket.accept()
  connstream = context.wrap_socket(newsocket, server_side=True)
  try:
    data = connstream.recv(1024)
    connstream.send(b'mTLS protected\n')
  finally:
    connstream.shutdown(socket.SHUT_RDWR)
    connstream.close()

After applying these fixes, rerun middleBrick (via CLI, GitHub Action, or MCP Server) to confirm that the missing authentication finding no longer appears and that the overall security score improves.

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

What is the difference between missing authentication in regular TLS and Mutual TLS?
In regular TLS only the server authenticates to the client; missing authentication means the server presents an invalid or untrusted certificate, allowing a client to be tricked into talking to an impostor. In Mutual TLS both sides must authenticate each other, so missing authentication can occur on the server side (failing to request or validate a client certificate) or on the client side (failing to validate the server’s certificate). Both enable impersonation, but Mutual TLS adds the risk of unauthorized clients connecting to the service when server‑side client auth is disabled.
Can middleBrick detect missing authentication if the API is behind a load balancer that terminates TLS?
Yes. middleBrick evaluates the TLS handshake as seen from the public endpoint. If the load balancer terminates TLS and does not forward client certificate information to the backend, the scanner will observe that the load balancer accepts connections without a valid client cert and will report missing client authentication at the edge. If the load balancer forwards the client cert but the backend ignores it, middleBrick’s handshake‑level checks still succeed, and the finding will be attributed to the API service because the scanner receives an application‑level response only after the backend processes the request.