HIGH information disclosuremutual tls

Information Disclosure with Mutual Tls

How Information Disclosure Manifests in Mutual TLS

Mutual TLS (mTLS) adds client‑certificate authentication to the standard TLS handshake. While this strengthens authentication, it also introduces new avenues for information disclosure if the implementation is not carefully hardened.

  • Verbose handshake error messages – When a client presents an invalid or expired certificate, some TLS stacks return detailed alert messages (e.g., "certificate unknown", "certificate revoked") that can be observed in the TCP stream or in application logs. An attacker who can provoke handshake failures learns whether a particular certificate serial number is known to the server, leaking internal PKI structure.
  • Logging of client certificate data – Developers often log the entire client certificate (subject, issuer, serial number) for debugging. If those logs are accessible (e.g., via debug endpoints, error pages, or log aggregation services), an attacker can harvest internal distinguished names, organizational units, or certificate policy OIDs that reveal internal hierarchy.
  • Exposure of private key material via misconfigured TLS context – In environments where the server’s private key is loaded from a file with overly permissive permissions, or where the key is accidentally included in a debug dump (e.g., console.log(tlsContext) in Node.js), the private key can be exfiltrated. With the key, an attacker can decrypt passive traffic or impersonate the server.
  • Weak or anonymous cipher suites – If the server permits NULL or anonymous DH ciphers (e.g., TLS_DH_anon_WITH_AES_128_CBC_SHA), the handshake proceeds without authenticating either party. Although the session keys are still exchanged, the lack of authentication can lead to downgrade attacks where an attacker forces the use of a suite that leaks more information through side‑channels.
  • Certificate transparency (CT) leakage – Some mTLS implementations embed SCTs (Signed Certificate Timestamps) in the certificate chain. If the server reflects these SCTs in error responses or debug pages, an attacker can infer which certificates have been logged publicly, potentially mapping internal services to public CT logs.

These patterns fall under OWASP API3:2019 – "Excessive Data Exposure" and also map to the "Information Disclosure" category in the OWASP API Security Top 10.

Mutual TLS‑Specific Detection

Detecting information disclosure in mTLS requires looking for the symptoms described above, both in network traffic and in application output. middleBrick’s unauthenticated black‑box scan includes checks that surface these issues:

  • Data Exposure check – Scans HTTP responses (including TLS alert messages that may be reflected in error pages) for strings that resemble certificate fields (e.g., "CN=", "O=", "serialNumber"). If such strings appear in a 4xx/5xx response, the check flags a potential leak.
  • Encryption check – Evaluates the TLS configuration presented during the handshake. It reports if the server allows anonymous or NULL cipher suites, if TLS versions below 1.2 are enabled, or if the server’s certificate chain contains SCTs that are reflected in clear text.
  • Authentication check – Verifies whether the server actually requires a valid client certificate. If the handshake succeeds without presenting a client cert (or with a clearly invalid one) and the server still proceeds to process the request, the check notes missing enforcement, which can lead to error‑message leakage.
  • LLM/AI Security check (when relevant) – For APIs that expose LLM endpoints over mTLS, the scanner also probes for prompt injection that could cause the model to echo back internal certificate data.

Example CLI usage to scan an mTLS‑protected API:

# Install the middleBrick CLI (npm)
npm i -g middlebrick
# Scan a host that expects mutual TLS
middlebrick scan https://api.internal.example.com --client-cert ./client.crt --client-key ./client.key

The command returns a JSON report where the findings array will contain entries such as:

{
  "id": "DATA_EXP_004",
  "name": "Certificate details exposed in error response",
  "severity": "medium",
  "description": "The response body contains the string 'CN=internal-ca, O=Example Corp' which may reveal internal PKI hierarchy.",
  "remediation": "Strip certificate‑specific data from error messages and logs. Use generic error texts instead."
}

In a CI/CD pipeline, the GitHub Action can be configured to fail the build if any finding with severity ≥ medium is detected:

name: API Security Scan
on: [push]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run middleBrick scan
        uses: middlebrick/github-action@v1
        with:
          api-url: https://staging.api.example.com
          client-cert: ${{ secrets.CLIENT_CERT }}
          client-key: ${{ secrets.CLIENT_KEY }}
          fail-on-severity: medium

This approach gives developers immediate feedback when a configuration change unintentionally exposes certificate‑related information.

Mutual TLS‑Specific Remediation

Fixing information disclosure in mTLS focuses on eliminating unnecessary data exposure while preserving strong mutual authentication.

  • Suppress certificate data in logs and error messages – Configure your TLS library to avoid logging the full client certificate. In Node.js, set the secureContext options and use a custom secureConnection listener that only logs the result of the verification, not the certificate itself:
const tls = require('tls');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt'),
  ca: fs.readFileSync('ca.crt'),
  requestCert: true,   // require client cert
  rejectUnauthorized: true, // reject if client cert invalid
  // Do NOT log client cert details
};

const server = tls.createServer(options, (cleartextStream) => {
  // The client certificate is available via cleartextStream.getPeerCertificate()
  // but we only log the verification result
  const cert = cleartextStream.getPeerCertificate();
  if (cert) {
    console.log(`Client cert verified: ${cert.subject.commonName}`);
  } else {
    console.log('No client certificate presented');
  }
  cleartextStream.write('HTTP/1.1 200 OK\r\n\r\nOK');
  cleartextStream.end();
});

server.listen(8443);
  • Disable anonymous and weak cipher suites – Explicitly define a strong cipher list. In OpenSSL‑based stacks (Node.js, Python’s ssl module) you can set the ciphers option to exclude NULL and anonymous DH:
# Python example using ssl.SSLContext
import ssl, socket

context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile='server.crt', keyfile='server.key')
context.load_verify_locations(cafile='ca.crt')
context.verify_mode = ssl.CERT_REQUIRED
# Strong cipher suite: exclude NULL, anonymous, and weak ciphers
context.set_ciphers('ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA')

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.bind(('0.0.0.0', 8443))
    sock.listen(5)
    while True:
        conn, addr = sock.accept()
        with context.wrap_socket(conn, server_side=True) as ssock:
            # Handle request without leaking cert data
            ssock.sendall(b'HTTP/1.1 200 OK\r\n\r\nOK')
  • Ensure proper error handling – Catch TLS errors and return generic HTTP status codes (e.g., 400 Bad Request) without embedding TLS alert descriptions. In Express, you can use an error‑handling middleware that strips TLS‑specific details:
app.use((err, req, res, next) => {
  if (err.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ||
      err.code === 'CERT_HAS_EXPIRED' ||
      err.code === 'SELF_SIGNED_CERT_IN_CHAIN') {
    // Generic response – no PKI details
    return res.status(400).send('Invalid client certificate');
  }
  next(err);
});
  • Protect private key material – Ensure the key file is readable only by the process owner (chmod 600 server.key) and never include it in container images or source control. Use secret‑management systems (e.g., HashiCorp Vault, AWS Secrets Manager) to load the key at runtime.

After applying these fixes, re‑run middleBrick (via CLI, GitHub Action, or the Dashboard) to verify that the Data Exposure and Encryption checks no longer report findings related to certificate leakage.

Frequently Asked Questions

Does middleBrick decrypt mutual TLS traffic to inspect application data?
No. middleBrick performs unauthenticated black‑box scanning from the outside. It observes the TLS handshake, certificate exchange, and any application‑level responses, but it never decrypts or accesses the encrypted payload.
Can I use middleBrick to verify that my mTLS configuration disables anonymous cipher suites?
Yes. The Encryption check in the scan reports whether the server offers NULL or anonymous DH ciphers. If such suites are detected, the finding will advise you to restrict the cipher list to strong, authenticated suites only.