Auth Bypass in Adonisjs with Basic Auth
Auth Bypass in Adonisjs with Basic Auth — how this specific combination creates or exposes the vulnerability
AdonisJS is a Node.js web framework that provides built-in authentication helpers, including support for Basic Auth via the @adonisjs/auth package. When Basic Auth is used without strict scope and session validation, it can contribute to an Auth Bypass (also categorized as BOLA/IDOR and Broken Access Control). An Auth Bypass occurs when authorization checks are incomplete or misapplied, allowing one user to access or modify the resources of another.
Basic Auth in AdonisJS typically relies on a user identifier (such as a username or email) and a password. If routes that expose sensitive endpoints (e.g., /users/:id or /accounts/:accountId) do not enforce that the authenticated user’s identity matches the requested resource identifier, an attacker may change the URL parameter to access another user’s data. This becomes an Auth Bypass when route-level guards assume the presence of a valid user session or token but do not re-validate ownership or permissions on each request.
For example, an endpoint like GET /api/users/:userId might retrieve user details using the route parameter userId. If the handler only checks that a user is authenticated and directly uses userId to query the database without confirming that the authenticated user’s ID matches userId, an attacker can supply any numeric ID to view other accounts. MiddleBrick’s checks for BOLA/IDOR and Property Authorization are designed to surface these gaps by comparing runtime requests against expected authorization boundaries defined in an OpenAPI spec.
In addition to route-level mismatches, Basic Auth–based APIs may inadvertently expose sensitive functionality when CORS, route naming, or middleware ordering is misconfigured. Middleware that applies globally may skip ownership checks for certain paths, while OpenAPI specs that do not accurately reflect runtime behavior can cause the scanner to find discrepancies between declared scopes and actual enforcement. These gaps are especially relevant when endpoints combine Basic Auth with role-based assumptions but lack explicit checks tying each request to the authenticated user’s identity and entitlements.
Because Basic Auth transmits credentials with every request, it is crucial to enforce HTTPS to prevent credential exposure in transit. Even with encryption, developers must avoid treating the presence of a logged-in user as sufficient authorization. Each request that accesses or modifies a resource must recompute the allowed scope and compare it against the authenticated subject. Tools like middleBrick validate these controls by correlating spec-defined security schemes with observed behavior, highlighting missing or inconsistent authorization logic.
Basic Auth-Specific Remediation in Adonisjs — concrete code fixes
To mitigate Auth Bypass risks when using Basic Auth in AdonisJS, explicitly validate that the authenticated user matches the resource being accessed. Always resolve the user from the request authentication layer and compare identifiers before querying or mutating data.
Example: Secure User Profile Endpoint
Instead of trusting a route parameter, derive the user from the authenticated context:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import User from 'App/Models/User'
export default class UsersController {
public async show({ auth, params }: HttpContextContract) {
// auth.user is guaranteed to exist because auth middleware enforced it
const user = auth.user
// Ensure the requested ID matches the authenticated user’s ID
if (user.id !== params.id) {
return Response.badRequest('Unauthorized resource access')
}
return user
}
}
Example: Scope-Based Authorization with Policies
Use AdonisJS policies to encapsulate permission logic and reuse it across routes:
import { BasePolicy } from '@ioc:Adonis/Core/Policy'
import User from 'App/Models/User'
import Post from 'App/Models/Post'
export default class PostPolicy extends BasePolicy {
public async view(user: User, postId: number) {
const post = await Post.find(postId)
if (!post) {
return false
}
// Only allow access if the post belongs to the user
return post.userId === user.id
}
}
Register the policy and protect routes accordingly:
import Route from '@ioc:Adonis/Core/Route'
import PostPolicy from 'App/Policies/PostPolicy'
Route.resource('posts', 'PostsController')
.authorize('posts', 'PostPolicy')
Example: Enforce HTTPS and Validate Content-Type
Ensure all authentication and sensitive endpoints require secure transport and well-formed payloads:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext')
Route.group(() => {
Route.post('/login', async ({ request, auth }) => {
// Require HTTPS in production-like checks (enforce at infrastructure level)
const { username, password } = request.only(['username', 'password'])
await auth.attempt(username, password)
return { ok: true }
}).middleware(['force-https'])
})
.prefix('api')
.as('auth.')
Operational Practices
- Always resolve the user via
auth.userrather than constructing models from route parameters. - Apply route-level middleware that guarantees authentication before reaching handlers.
- Use policies to centralize ownership checks and avoid duplicating authorization logic.
- Correlate your OpenAPI spec’s security schemes with actual route guards; middleBrick can highlight mismatches between declared and implemented controls.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |