Token Leakage in Adonisjs
How Token Leakage Manifests in Adonisjs
Token leakage in Adonisjs applications occurs when authentication tokens—whether JWTs, API keys, or session identifiers—are inadvertently exposed through logs, error responses, or insecure storage mechanisms. Adonisjs's middleware-based architecture and logging system create specific patterns where this vulnerability commonly appears.
The most frequent manifestation occurs in Adonisjs's built-in logger. By default, Adonisjs logs all request data, including headers, query parameters, and body content. When authentication tokens are included in these request components, they appear verbatim in log files. Consider this typical Adonisjs route handler:
Route.post('auth/login', async ({ auth, request, response }) => {
const { email, password } = request.body()
const token = await auth.attempt(email, password)
logger.info('Login successful', { user: email, token })
return response.ok({ token })
})Here, the token is logged directly, creating a persistent record in log files that may be accessible to unauthorized users or stored in less-secure locations. The same issue appears when tokens are included in error responses—Adonisjs's default error handling may expose stack traces containing token values.
Another Adonisjs-specific pattern involves the HttpContext object. When developers log the entire context for debugging:
Route.get('profile', async ({ auth, response }) => {
logger.debug('User context', auth.ctx)
return response.ok(await User.find(auth.user.id))
})The auth.ctx object contains the token, which gets logged in plaintext. Additionally, Adonisjs's session management can leak tokens if sessions are stored in databases without proper encryption, or if session IDs are exposed through URL parameters in development environments.
Adonisjs-Specific Detection
Detecting token leakage in Adonisjs requires examining both code patterns and runtime behavior. Start by auditing your route handlers for direct token logging:
grep -r "logger\.\|console\.log" | grep -E "(token|auth|jwt)" Look for patterns where tokens are passed directly to logging functions or included in response objects. Next, examine your auth configuration in config/auth.js:
module.exports = {
authenticator: 'jwt',
secret: Env.get('APP_KEY'),
expiry: '1 days',
// Check if tokens are being logged in middleware
logging: false // Set to false to prevent auth logging
}Adonisjs's middleware stack can be inspected to identify where tokens might be exposed. The auth middleware, by default, attaches tokens to the request context, making them accessible throughout the request lifecycle.
middleBrick's API security scanner specifically detects token leakage in Adonisjs applications by:
- Scanning for hardcoded tokens in configuration files
- Detecting tokens in response bodies through black-box testing
- Identifying insecure logging patterns through code analysis
- Checking for tokens in error responses and stack traces
The scanner's LLM/AI Security module also tests for system prompt leakage if you're using Adonisjs with AI integrations, which is particularly relevant for applications using AdonisJS Lucid models with AI-generated content.
For runtime detection, enable Adonisjs's request logging middleware with filtering:
const { route } = use('@adonisjs/core/http2/route')
Route
.get('/api/*', async (ctx) => {
// Request logging with token masking
const maskedHeaders = Object.fromEntries(
Object.entries(ctx.request.headers()).map(([key, value]) =>
key.toLowerCase().includes('authorization') ? [key, 'REDACTED'] : [key, value]
)
)
logger.info('API request', { headers: maskedHeaders })
return await next(ctx)
})
.use(async (ctx, next) => {
// Mask tokens in response logging
const originalSend = ctx.response.send.bind(ctx.response)
ctx.response.send = async (body) => {
if (body?.token) body.token = 'REDACTED'
return originalSend(body)
}
return next(ctx)
})Adonisjs-Specific Remediation
Remediating token leakage in Adonisjs requires a layered approach using the framework's built-in features. Start with the logger configuration in config/app.js:
module.exports = {
logger: {
transport: 'file',
level: 'info',
// Mask sensitive data in logs
mask: ['password', 'token', 'authorization', 'api_key', 'secret']
}
}This configuration automatically redacts sensitive fields from log entries. For more granular control, create a custom logging middleware:
const { Service } = require('@adonisjs/core/di')
class SecureLogger extends Service {
constructor(logger) {
this.logger = logger
}
info(message, context = {}) {
const sanitized = this.sanitize(context)
this.logger.info(message, sanitized)
}
sanitize(obj) {
if (typeof obj !== 'object' || obj === null) return obj
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => {
if (key.match(/token|auth|key|secret/i)) {
return [key, value ? 'REDACTED' : value]
}
if (typeof value === 'object') {
return [key, this.sanitize(value)]
}
return [key, value]
})
)
}
}
module.exports = SecureLoggerImplement token-aware error handling by extending Adonisjs's error handler:
const { Service } = require('@adonisjs/core/di')
class SecureErrorHandler extends Service {
async handle(error, { response }) {
// Remove tokens from error context
if (error.context) {
error.context = Object.fromEntries(
Object.entries(error.context).filter(([key]) =>
!key.match(/token|auth|key|secret/i)
)
)
}
response.status(error.status || 500).json({
error: error.message,
code: error.code,
// Never expose tokens in error responses
})
}
}
module.exports = SecureErrorHandlerFor API responses, implement a response wrapper that automatically masks tokens:
const { Service } = require('@adonisjs/core/di')
class SecureResponse extends Service {
constructor(response) {
this.response = response
}
ok(data, options = {}) {
const sanitized = this.sanitize(data)
return this.response.ok(sanitized, options)
}
sanitize(data) {
if (typeof data !== 'object' || data === null) return data
if (data.token) data.token = 'REDACTED'
return Object.fromEntries(
Object.entries(data).map(([key, value]) => {
if (typeof value === 'object') {
return [key, this.sanitize(value)]
}
return [key, value]
})
)
}
}
module.exports = SecureResponseFinally, integrate middleBrick's CLI into your development workflow to continuously scan for token leakage:
# Install middleBrick CLI
npm install -g middlebrick
# Scan your Adonisjs API
middlebrick scan https://your-api.com --type=adonisjs --output=json > report.json
# Add to package.json scripts
"scripts": {
"security:scan": "middlebrick scan https://your-api.com --type=adonisjs"
}This combination of code patterns, middleware, and automated scanning ensures comprehensive protection against token leakage in Adonisjs applications.