Data Exposure in Adonisjs with Api Keys
Data Exposure in Adonisjs with Api Keys
AdonisJS offers a flexible system for authenticating requests via API keys, typically managed through packages such as @adonisjs/auth or custom guards. When API keys are used without strict scoping, overly permissive routes, or proper validation, sensitive data can be exposed beyond the intended consumer. A common pattern is to register an API key guard and attach it to routes that return user profiles, billing information, or administrative views. If a route does not enforce scope restrictions or role-based checks, an attacker who obtains or guesses a key can read data that should be limited to specific tenants or permission sets.
Consider a route that lists user activity logs. Without explicit authorization checks tying the key to a specific user or organization, any key with access to that endpoint can view logs belonging to other users. The risk increases when API keys are passed in URLs or non-HTTPS environments, as they can be leaked in logs, browser history, or network traces. Even when keys are stored securely, developers might inadvertently include sensitive fields (such as email, password hashes, or internal IDs) in the serialized response because the controller does not filter the payload. AdonisJS does not automatically strip these fields, so the API can expose more data than the developer intends.
Another exposure vector involves endpoint discovery and metadata. If your AdonisJS application serves an OpenAPI spec at a route like /swagger.json without access controls, an attacker can enumerate all API keys–protected endpoints and infer the data landscape. Even when keys are validated, improper error handling can reveal whether a key exists or which fields are present in a record, aiding enumeration. For example, a 403 response might indicate authorization failure, while a 404 suggests the resource does not exist, allowing an attacker to map the data surface. Inconsistent rate limiting on key–authenticated routes can also enable low–speed scraping, where an attacker iterates over identifiers to harvest data piece by piece without tripping defenses.
Data exposure is not limited to the primary resource. Related resources loaded through relationships or included via query parameters can inadvertently disclose nested information. An endpoint that returns a user profile with an included subscription relationship might expose billing details if the API key has broader read permissions than intended. Because AdonisJS relies on developer-defined policies and guards, the framework does not automatically enforce least privilege. If policies are not aligned with key scopes, or if keys are shared across services, the blast radius of a leaked key expands. This is especially relevant when keys are long–lived or when rotation practices are inconsistent.
To illustrate a typical vulnerable setup, an AdonisJS project might define an API key guard in start/auth.ts and apply it to a route group. The controller then fetches records and returns them without filtering sensitive columns or enforcing record ownership. Because the scan tests unauthenticated attack surfaces, middleBrick can detect endpoints that accept API key identifiers as parameters but lack proper authorization, leading to data exposure findings. Remediation focuses on tightening scope, validating relationships, and ensuring responses contain only necessary data, which is covered in the next section.
Api Keys-Specific Remediation in Adonisjs
Remediation centers on precise scoping, strict validation, and minimal data exposure. Define a dedicated API key guard with limited permissions, and avoid reusing the same key across unrelated services. Use policy checks to ensure that a key can only access resources belonging to its owner or tenant. In AdonisJS, you can implement this by customizing the auth provider and adding explicit checks in routes or controllers.
Example of a scoped guard definition in start/auth.ts:
import { AuthConfig } from '@adonisjs/auth/types';
const authConfig: AuthConfig = {
guard: 'api_key',
providers: {
apiKey: {
driver: 'api_key',
model: 'App/Models/User',
keyField: 'api_key',
scope: 'tenant',
},
},
};
export default authConfig;
In your controller, enforce record ownership and filter sensitive fields before serialization:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import ActivityLog from 'App/Models/ActivityLog'
export default class ActivityLogsController {
public async index({ request, auth }: HttpContextContract) {
const keyUser = auth.getUserOrFail()
const logs = await ActivityLog.query()
.where('tenant_id', keyUser.tenantId)
.preload('user', (userQuery) => {
userQuery.select('id', 'username')
})
.select('id', 'action', 'created_at')
.orderBy('created_at', 'desc')
.limit(100)
return logs
For endpoints that reference a specific resource by ID, validate that the key is allowed to access that record:
import Invoice from 'App/Models/Invoice'
public async show({ params, auth }: HttpContextContract) {
const keyUser = auth.getUserOrFail()
const invoice = await Invoice.query()
.where('id', params.id)
.where('tenant_id', keyUser.tenantId)
.firstOrFail()
return invoice.serialize({ fields: ['id', 'amount', 'status', 'due_date'] })
}
Rotate keys regularly and avoid embedding them in URLs. When returning JSON, explicitly select fields to prevent leakage of internal columns such as password_hash or remember_token. Combine these practices with route-level policies and consistent error handling to reduce the risk of data exposure. middleBrick can verify that endpoints with key–based access enforce these constraints and do not return excessive data, supporting a more secure API surface.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |