HIGH data exposureadonisjsmutual tls

Data Exposure in Adonisjs with Mutual Tls

Data Exposure in Adonisjs with Mutual Tls

Mutual Transport Layer Security (mTLS) in AdonisJS can inadvertently contribute to data exposure when certificate-based authentication is present but application-layer data handling remains inconsistent. mTLS ensures both client and server authenticate each other using X.509 certificates, which strengthens channel security. However, if the application logic does not enforce strict authorization on sensitive data after authentication, mTLS alone does not prevent IDOR or BOLA-style access to resources. In AdonisJS, developers often rely on the presence of a valid client certificate to infer identity, but they may fail to verify whether that authenticated identity is permitted to access the specific resource requested.

For example, an endpoint like GET /api/users/:id might verify the client certificate and extract a subject field such as CN=user-123, but then directly use the route parameter :id to query the database without confirming that user-123 owns the record with the requested ID. This mismatch between transport-layer authentication (mTLS) and application-level authorization creates a data exposure window where one authenticated user can view or modify another user’s data. The risk is amplified when responses include sensitive fields such as email, phone number, or internal identifiers, and those fields are not filtered based on the authenticated identity derived from the certificate.

middleBrick detects this category of exposure by correlating mTLS authentication signals with data access patterns. It checks whether responses contain data that should be restricted based on the identity indicated by the client certificate, and whether authorization checks are consistently applied across endpoints. Findings often highlight missing ownership validation, overly broad role claims in certificate attributes, or inconsistent use of scoped queries. Remediation guidance emphasizes tying certificate-derived identities to data ownership models and applying per-request filters so that data exposure is limited strictly to what the authenticated subject is allowed to see.

Real-world CVEs in related frameworks illustrate the risk: vulnerabilities tagged under OWASP API Top 10 A1 (Broken Object Level Authorization) and A6 (Security Misconfiguration) often map to these patterns. For instance, improper handling of authenticated identity after mTLS handshake can lead to exposures similar to insecure direct object references, where predictable numeric IDs enable horizontal privilege escalation. Because mTLS is commonly perceived as providing complete security, such issues may remain undetected without active scanning that combines spec analysis and runtime testing, as performed by middleBrick in its unauthenticated black-box scans.

Mutual Tls-Specific Remediation in Adonisjs

To remediate data exposure risks in AdonisJS when using mTLS, you must enforce strict mapping between the certificate identity and data access scopes. This means that after the TLS handshake completes and the client certificate is validated, the application should extract a stable subject or serial identifier and use it to filter all data queries. Never rely on route parameters alone to determine data ownership; always cross-check the certificate-bound identity against the resource owner.

Below are concrete code examples that demonstrate how to implement mTLS-aware authorization in AdonisJS routes and providers.

1. Configure mTLS in the AdonisJS server

Enable client certificate verification at the server level. In start/server.ts, ensure the HTTPS server requests but does not necessarily require client certificates, allowing application logic to decide strictness:

import { HttpServer } from '@adonisjs/core/server'

export default class AppServer extends HttpServer {
  protected ssl = {
    cert: '/path/to/ca-bundle.pem',
    key: '/path/to/server-key.pem',
    requestCert: true,
    rejectUnauthorized: false, // app will validate after inspecting cert
  }
}

2. Extract identity from the client certificate

Create an around middleware or an auth provider that reads the peer certificate and normalizes the identity. This example uses a middleware that attaches the subject to the authentication guard:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class MtlsIdentityMiddleware {
  public async handle(ctx: HttpContextContract, next: () => Promise<void>) {
    const request = ctx.request
    const socket = request.getRaw()
    // @ts-ignore — peerCertificate is available on Node.js TLS socket
    const cert = socket.getPeerCertificate()

    if (!cert.subject) {
      ctx.response.unauthorized('Client certificate missing subject')
      return
    }

    // Normalize identity; prefer a custom SAN or CN field
    const subject = cert.subject.CN || cert.subject.commonName
    if (!subject) {
      ctx.response.unauthorized('Client certificate subject is not recognized')
      return
    }

    // Attach identity to the context for downstream use
    ctx.auth.user = { mtlsSubject: subject } as any
    await next()
  }
}

3. Apply scoping in controllers

In your resource controller, use the mTLS-bound identity to filter queries. For a user profile endpoint, ensure the requested ID matches the certificate identity:

import User from 'App/Models/User'

export default class UsersController {
  public async show({ params, auth }: HttpContextContract) {
    const user = await User.query()
      .where('id', params.id)
      .where('mtls_subject', auth.user?.mttlsSubject)
      .preload('profile')
      .firstOrFail()

    return user
  }
}

4. Enforce scoping in providers and policies

For broader protection, implement a policy that checks ownership using the certificate identity before allowing updates or deletes:

import { BasePolicy } from '@ioc:Adonis/Core/Policy'

export default class ResourcePolicy extends BasePolicy {
  public async update(ownerMtlsSubject: string, record: any) {
    return record.mtls_subject === ownerMtlsSubject
  }

  public async delete(ownerMtlsSubject: string, record: any) {
    return record.mtls_subject === ownerMtlsSubject
  }
}

By combining mTLS authentication with explicit data ownership checks, you reduce the chance of data exposure across endpoints. middleBrick’s scans can validate that such scoping is consistently applied and flag endpoints that accept identifiers without verifying them against the certificate-derived identity.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Does mTLS prevent data exposure in AdonisJS by itself?
No. mTLS authenticates the client and server at the transport layer, but data exposure risks remain if the application does not enforce authorization and ownership checks on resources. Always couple mTLS with per-request identity-based scoping.
How does middleBrick detect data exposure related to mTLS in AdonisJS?
middleBrick correlates authentication signals from mTLS with runtime data access patterns. It checks whether responses contain data that should be restricted based on the certificate identity and whether authorization checks are consistently applied across endpoints.