Insecure Direct Object Reference in Adonisjs with Basic Auth
Insecure Direct Object Reference in Adonisjs with Basic Auth — how this specific combination creates or exposes the vulnerability
Insecure Direct Object Reference (IDOR) occurs when an API exposes internal object references, such as database keys or record IDs, without verifying that the authenticated caller has permission to access the specific resource. In AdonisJS, this commonly arises when a route uses a parameter (e.g., id) to look up a model and returns it directly, relying only on authentication rather than authorization scoped to the requesting user.
When Basic Auth is used in AdonisJS, the framework typically validates credentials (often via an auth middleware) and attaches a user identity to the request. However, if route handlers then use request parameters to fetch resources without confirming ownership or access rights, the presence of authenticated Basic Auth can create a false sense of security. For example, consider a route /users/:id/profile protected with Basic Auth. An authenticated user could simply change :id to another user’s numeric identifier; because the handler does not enforce that the authenticated user’s ID matches the requested :id, the record is returned. This is an IDOR vulnerability: the application reveals data due to missing ownership checks, even though authentication succeeded.
AdonisJS does not automatically enforce object-level permissions. If your application uses route-based identifiers and Basic Auth for authentication, you must explicitly gate access. Common patterns that lead to IDOR include:
- Using
User.findOrFail(request.param('id'))without verifying that the authenticated user’s ID equalsrequest.param('id'). - Querying relationships without scoping by the authenticated user, e.g.,
await Post.query().where('id', request.param('postId')).first()without ensuring the authenticated user owns or has access to that post. - Exposing internal IDs in URLs that an attacker can enumerate, especially when rate limiting or access logging is insufficient.
IDOR is frequently linked to other checks in middleBrick’s scan suite, such as BOLA/IDOR and Property Authorization. Even when Basic Auth is correctly implemented, missing authorization logic can cause sensitive information to be disclosed, violating principles like least privilege and data exposure controls from frameworks such as OWASP API Top 10.
To illustrate, here is an unsafe AdonisJS route using Basic Auth that is vulnerable to IDOR:
// routes.ts
Route.get('/users/:id/profile', async ({ request, auth }) => {
const user = await User.findOrFail(request.param('id'));
return user.profile;
});
// StartAuth.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export default class StartAuth {
public async handle({ request, auth, response }: HttpContextContract, next: () => Promise) {
await auth.check();
await next();
}
}
In this example, auth.check() ensures a valid Basic Auth user exists, but the route does not verify that the authenticated user’s ID matches request.param('id'). An authenticated user can change the URL to access any profile, resulting in IDOR. This demonstrates that authentication alone is insufficient; explicit authorization checks are required to prevent unauthorized data access.
Basic Auth-Specific Remediation in Adonisjs — concrete code fixes
To remediate IDOR when using Basic Auth in AdonisJS, you must enforce that the authenticated user is authorized to access the requested resource. This typically involves comparing the authenticated user’s identifier with the identifier in the request and scoping queries accordingly.
Here is a secure pattern for a user profile endpoint:
// routes.ts
Route.get('/users/:id/profile', 'UserProfileController.show').middleware('auth')
// UserProfileController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import User from 'App/Models/User';
export default class UserProfileController {
public async show({ request, auth }: HttpContextContract) {
const authenticatedUser = auth.user!;
const requestedId = request.param('id');
if (authenticatedUser.id !== requestedId) {
throw response.forbidden('Unauthorized access');
}
const user = await User.findOrFail(requestedId);
return user.profile;
}
}
For nested resources, such as posts owned by a user, scope the query to the authenticated user:
// routes.ts
Route.get('/users/:userId/posts/:postId', 'UserPostController.show').middleware('auth')
// UserPostController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import Post from 'App/Models/Post';
export default class UserPostController {
public async show({ request, auth, response }: HttpContextContract) {
const user = auth.user!;
const userId = request.param('userId');
const postId = request.param('postId');
if (user.id !== userId) {
return response.forbidden('Unauthorized');
}
const post = await Post.query()
.where('user_id', user.id)
.andWhere('id', postId)
.firstOrFail();
return post;
}
}
These patterns ensure that even when Basic Auth confirms identity, access is constrained by explicit checks. You can centralize these checks in route middleware or service layers to keep controllers clean and consistent. middleBrick’s scans can help detect missing authorization by correlating authentication state with object-level access patterns; findings often map to compliance frameworks such as OWASP API Top 10 and SOC2. If you want continuous visibility, consider the Pro plan for continuous monitoring and alerts when risk scores change, or integrate the CLI into scripts with middlebrick scan <url> to automate detection during development.
For teams using CI/CD, the GitHub Action can add API security checks to your pipeline and fail builds if risk scores drop below your chosen threshold, helping catch IDOR regressions before deployment. Similarly, the MCP Server allows you to scan APIs directly from your AI coding assistant within the IDE, providing rapid feedback while writing route handlers.
Related CWEs: bolaAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-250 | Execution with Unnecessary Privileges | HIGH |
| CWE-639 | Insecure Direct Object Reference | CRITICAL |
| CWE-732 | Incorrect Permission Assignment | HIGH |