HIGH data exposureadonisjsjwt tokens

Data Exposure in Adonisjs with Jwt Tokens

Data Exposure in Adonisjs with Jwt Tokens

The combination of AdonisJS and JWT tokens can unintentionally expose sensitive data when tokens are handled without strict constraints. AdonisJS applications often use the jwt provider to issue and verify tokens, but misconfigurations may cause the framework to embed or leak sensitive payload contents in logs, error messages, or responses. For example, if a token payload contains a user identifier, role, or email and the application reflects that payload in API responses without filtering, an authenticated endpoint may disclose PII or authorization-relevant data to unintended clients.

Data exposure in this context also arises when tokens are transmitted over non-encrypted channels. Even if AdonisJS generates secure JWTs, failing to enforce HTTPS can allow intermediaries to observe tokens and the claims they carry. A typical pattern that increases risk is serializing broad claims (such as permissions or scopes) into the token and then including those claims in JSON responses, effectively amplifying the data footprint of each token. The framework’s default behavior does not automatically redact sensitive claims, so developers must consciously limit what is stored in the JWT and how it is surfaced to the client.

Another vector specific to AdonisJS is verbose error handling during token verification. When a token is malformed or expired, stack traces or detailed messages may include parts of the token payload if the error handling logic is not constrained. These messages can be returned to API consumers and expose internal structures or data fragments. The risk is compounded when the token carries sensitive information such as user identifiers or roles, because an attacker can harvest details that facilitate privilege escalation or social engineering. Proper exception handling and minimal error feedback are required to prevent token-related data exposure.

Middleware and guards in AdonisJS can also contribute to exposure if they inadvertently pass token payloads through to downstream handlers or logging mechanisms. For instance, attaching the entire token payload to the request context for convenience may simplify development but increases the surface area for accidental leakage through logs or debugging endpoints. Even in unauthenticated attack surface scans, middleBrick tests for Data Exposure by checking whether responses include sensitive payload fragments, and findings often highlight places where JWT claims are reflected without sanitization.

To contextualize the severity, data exposure through JWT tokens does not always imply direct access to secrets like the signing key, but it can degrade trust and violate privacy expectations. Findings typically map to controls in frameworks such as OWASP API Top 10 (API1:2023 Broken Object Level Authorization often coexists with excessive data exposure) and compliance regimes including GDPR and SOC2. middleBrick’s checks consider whether tokens or claims appear in responses, logs, or error objects, and prioritize remediation based on the sensitivity of the exposed data and the token’s scope.

Jwt Tokens-Specific Remediation in Adonisjs

Remediation focuses on minimizing what is stored in the JWT, protecting tokens in transit, and ensuring error handling does not reflect sensitive content. Below are concrete steps and code examples aligned with AdonisJS conventions.

1. Use minimal claims and avoid sensitive data in payloads

Do not store PII, emails, or internal identifiers directly in the token. Instead, store a user ID and fetch detailed claims from your data store when needed.

// start:token-creation-minimal
import { base64 } from '@ioc:AdonisJS/core/helpers'
import { DateTime } from 'luxon'
import { JwtProviderContract } from '@ioc:Adonis/Addons/Jwt'

export async function issueMinimalToken(user: UserContract) {
  const jwt = use('jwt') as JwtProviderContract
  const payload = {
    sub: user.id,               // only a reference ID
    iat: Math.floor(Date.now() / 1000),
    exp: DateTime.local().plus({ hours: 1 }).toSeconds()
  }
  return jwt.sign(payload)
}
// end:token-creation-minimal

2. Enforce HTTPS for all token transmission

Ensure your application forces HTTPS so tokens are not exposed in cleartext. In AdonisJS, you can set NODE_ENV=production and configure trust proxy headers appropriately.

// start:https-enforcement
// In start/hooks.ts or a dedicated middleware
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default function enforceHttps(ctx: HttpContextContract) {
  if (ctx.request.secure) {
    return
  }
  if (ctx.request.url() === '/login' || ctx.request.url() === '/token') {
    // Allow token endpoints only over HTTPS in production
    if (process.env.NODE_ENV === 'production') {
      ctx.response.redirect('https://' + ctx.request.header('host') + ctx.request.url())
    }
  }
}
// end:https-enforcement

3. Sanitize responses and avoid reflecting JWT claims

Ensure API responses do not echo back token payloads. Explicitly strip sensitive fields before serialization.

// start:sanitize-response
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export function sanitizeUserResponse(user: UserContract, token: string) {
  return {
    id: user.id,
    username: user.username,
    // do not include raw token or claims in the response body
    token: token.startsWith('Bearer ') ? token : `Bearer ${token}`
  }
}
// end:sanitize-response

4. Use structured error handling for token verification failures

Return generic messages and avoid leaking token contents in errors or logs.

// start:error-handling
import { Exception } from '@poppinss/utils'

export function handleJwtError() {
  try {
    const token = request.header('authorization')?.replace('Bearer ', '')
    if (!token) throw new Exception('Unauthorized', 401)
    const payload = jwt.verify(token, secret)
    return payload
  } catch (error) {
    // Do not include token or decoded payload in logs/messages
    logger.error('JWT verification failed', { error: error.message })
    throw new Exception('Invalid token', 401)
  }
}
// end:error-handling

5. Scope tokens and rotate secrets

Issue short-lived tokens and rotate signing keys regularly to reduce the impact of any leaked token.

// start:short-lived-issuance
export async function issueScopedToken(user: UserContract, scopes: string[]) {
  const jwt = use('jwt') as JwtProviderContract
  const payload = {
    sub: user.id,
    scope: scopes.join(' '),
    iat: Math.floor(Date.now() / 1000),
    exp: DateTime.local().plus({ minutes: 15 }).toSeconds()
  }
  return jwt.sign(payload)
}
// end:short-lived-issuance

6. Audit logging without sensitive content

Log token usage events (issue, verify, fail) without including the token string or its payload.

// start:audit-logging
export function auditTokenEvent(event: 'issue' | 'verify' | 'fail', userId: number) {
  logger.info(`JWT ${event}`, { userId, timestamp: new Date().toISOString() })
}
// end:audit-logging

7. Apply middleware guards consistently

Use AdonisJS middleware to protect routes and avoid manually parsing tokens in every handler.

// start:middleware-guard
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { exception } from '@poppinss/utils'

export const verifyJwt = async (ctx: HttpContextContract) => {
  const authHeader = ctx.request.header('authorization')
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    throw exception.unauthorized('Missing authorization header')
  }
  const token = authHeader.split(' ')[1]
  try {
    const payload = jwt.verify(token, secret)
    ctx.auth.user = { id: payload.sub } as any
  } catch {
    throw exception.unauthorized('Invalid token')
  }
}
// end:middleware-guard

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

What does middleBrick check for regarding Data Exposure with JWT tokens?
middleBrick checks whether JWT tokens or their claims appear in API responses, logs, or error messages without sanitization, and whether tokens are transmitted without encryption. Findings are prioritized by the sensitivity of exposed data and mapped to relevant compliance controls.
Can I use the free plan to scan APIs that use JWT tokens for authentication?
Yes, the free plan provides 3 scans per month and supports scanning any API endpoint, including those protected by JWT tokens. It tests the unauthenticated attack surface and includes checks for Data Exposure related to token handling.