Data Exposure in Adonisjs
How Data Exposure Manifests in Adonisjs
Data exposure in Adonisjs APIs often stems from model serialization vulnerabilities where sensitive fields are inadvertently included in API responses. Adonisjs's Lucid ORM makes it easy to accidentally expose fields like passwords, API keys, or internal IDs when using model instances directly in responses.
The most common pattern involves forgetting to use pick or omit when serializing models. Consider this vulnerable Adonisjs controller:
class UserController {
async show({ params }) {
const user = await User.find(params.id)
return user
}
}
This returns the entire User model instance, including any hidden fields that might be exposed through serialization. Adonisjs's toJson() method respects the hidden property on models, but direct model returns don't always trigger proper serialization.
Another Adonisjs-specific vulnerability occurs with eager loading relationships. When loading related models, developers might unintentionally expose sensitive data through nested relationships:
class PostController {
async index() {
const posts = await Post.query().preload('author')
return posts
}
}
If the User model has sensitive fields not properly hidden, or if the relationship includes sensitive pivot table data, this can leak information. Adonisjs's query builder makes it easy to chain operations that expose more data than intended.
Route parameter binding in Adonisjs can also lead to data exposure. When using route model binding with :id parameters, developers might not validate whether the authenticated user has permission to view that specific resource:
Route.get('users/:id', 'UserController.show')
Without proper authorization checks, this can expose user data to unauthorized parties. The findOrFail method throws a 404 for non-existent records, but doesn't verify permissions.
Adonisjs's middleware system can create data exposure if authentication middleware isn't properly configured. A common mistake is forgetting to apply authentication middleware to routes that should be protected, allowing unauthenticated access to sensitive data.
Finally, Adonisjs's support for multiple response formats can lead to accidental data exposure. If content negotiation isn't properly configured, an API might return sensitive data in formats intended only for debugging or internal use.
Adonisjs-Specific Detection
Detecting data exposure in Adonisjs requires both static analysis of your codebase and dynamic runtime scanning. Start by examining your model definitions for proper field hiding:
class User extends Model {
static get hidden() {
return ['password', 'api_key', 'ssn']
}
}
Check that all models containing sensitive data have appropriate hidden properties. Adonisjs provides this mechanism specifically to prevent data exposure, but it only works if properly implemented.
Review your controllers for direct model returns without serialization. Look for patterns like:
// Vulnerable
return user
// Secure
return user.serialize({ fields: ['id', 'name', 'email'] })
Examine relationship loading patterns. Adonisjs's preload and with methods can expose more data than intended. Check for:
// Check for unnecessary relationship loading
const users = await User.query().preload('profile')
Audit your route definitions for missing authentication middleware. In Adonisjs, middleware is applied at the route level:
Route.get('users/:id', 'UserController.show').middleware('auth')
Without the auth middleware, anyone can access these endpoints.
For comprehensive detection, use middleBrick's API security scanner. It specifically tests for data exposure vulnerabilities in Adonisjs applications by:
- Analyzing OpenAPI specs for exposed sensitive fields
- Scanning runtime responses for PII, passwords, and API keys
- Testing authentication bypass scenarios
- Checking for excessive data exposure in API responses
middleBrick's scanner runs in 5-15 seconds and requires no credentials or configuration. Simply provide your Adonisjs API URL and it will identify data exposure risks with specific remediation guidance.
middleBrick also analyzes your OpenAPI/Swagger specifications if available, cross-referencing defined schemas with actual runtime responses to catch mismatches that could indicate data exposure.
Adonisjs-Specific Remediation
Remediating data exposure in Adonisjs starts with proper model configuration. Always define hidden fields for any sensitive data:
class User extends Model {
static get hidden() {
return ['password', 'api_key', 'ssn', 'credit_card']
}
static get visible() {
return ['id', 'name', 'email', 'created_at']
}
}
The visible property provides an explicit whitelist approach, which is often more secure than relying on hidden alone.
For API responses, use explicit serialization rather than returning model instances directly:
class UserController {
async show({ params }) {
const user = await User.find(params.id)
// Secure approach - only return specific fields
return {
id: user.id,
name: user.name,
email: user.email,
created_at: user.created_at
}
}
}
Alternatively, use Adonisjs's built-in serialization:
return user.serialize({ fields: ['id', 'name', 'email'] })
For collections, use fetch with serialization:
const users = await User.query().select('id', 'name', 'email')
return users.map(user => user.serialize({ fields: ['id', 'name', 'email'] }))
Implement proper authorization checks using Adonisjs's policies or manual validation:
class UserController {
async show({ params, auth }) {
const user = await User.find(params.id)
// Check if authenticated user can view this resource
if (user.id !== auth.user.id) {
return response.status(403).send('Forbidden')
}
return user.serialize({ fields: ['id', 'name', 'email'] })
}
}
For relationship data, be explicit about what you're loading:
class PostController {
async show({ params }) {
const post = await Post.query()
.where('id', params.id)
.select('id', 'title', 'content', 'created_at')
.preload('author', (builder) => {
builder.select('id', 'name', 'email')
})
return post.serialize()
}
}
Always apply authentication middleware to protected routes:
Route.group(() => {
Route.get('users/:id', 'UserController.show')
Route.get('posts', 'PostController.index')
}).middleware('auth')
Consider using Adonisjs's API resource classes for consistent response formatting:
class UserResource {
static show(user) {
return {
id: user.id,
name: user.name,
email: user.email
}
}
}
Integrate middleBrick into your development workflow to continuously scan for data exposure. Add it as a GitHub Action to scan your Adonisjs API on every pull request:
- name: Run middleBrick Scan
uses: middlebrick/middlebrick-action@v1
with:
api-url: http://localhost:3333
fail-on-severity: high
This ensures data exposure vulnerabilities are caught before deployment. The Pro plan includes continuous monitoring that scans your Adonisjs API on a configurable schedule, alerting you if new data exposure risks are detected.
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 |
Frequently Asked Questions
How does Adonisjs's model serialization differ from other ORMs regarding data exposure?
hidden and visible properties on models that control serialization. Unlike some ORMs that require manual field selection, Lucid automatically respects these properties when using toJson() or serialize(). However, direct model returns in controllers bypass this protection, making it crucial to always use explicit serialization methods in Adonisjs APIs.