Dns Rebinding in Adonisjs with Jwt Tokens
Dns Rebinding in Adonisjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Dns Rebinding is a client-side network attack where a malicious webpage causes a victim’s browser to resolve a hostname to an IP address that changes over the course of a session, typically pivoting from a public address to a private one (e.g., 127.0.0.1). When AdonisJS applications rely on JSON Web Tokens (JWT) for authorization and are exposed via a public endpoint that does not enforce strict origin and host validation, this technique can bypass same-origin assumptions and expose internal services or admin interfaces.
In AdonisJS, JWTs are typically issued after authentication and sent in the Authorization header as Bearer tokens. If an endpoint that validates JWTs is reachable from the internet and does not enforce strict referrer or host policies, an attacker can serve a page that resolves the domain to 127.0.0.1 after authentication. The victim’s browser retains the JWT in memory or in an HTTP-only cookie (if used that way), and subsequent requests to the rebinding domain include the token, granting access to internal routes or admin panels that would otherwise be restricted. This is especially risky when JWT validation is performed per request without additional checks for the request origin, host header, or anti-rebinding defenses.
The attack flow is specific to the combination: the attacker tricks the victim into obtaining a valid JWT (e.g., via phishing or XSS), then uses DNS rebinding to make the browser send that token to an internal listener. Because AdonisJS may trust the Host header in certain configurations (e.g., when generating URLs for emails or when behind a proxy without strict header validation), the token validation logic may incorrectly consider the rebinding request as legitimate. The vulnerability is not in JWT itself but in how the application binds network identity to token authorization without corroborating DNS or IP constraints. Common misconfigurations include permissive CORS settings, missing Origin checks on token-introspection endpoints, and failure to validate the Host header against an allowlist.
To detect this class of issue, scans examine whether endpoints that verify JWTs also enforce strict origin and host policies, and whether they are exposed to untrusted networks without additional network-level restrictions. Findings highlight cases where token validation occurs without correlating the request’s network destination, enabling an attacker to reach internal routes via rebinding.
Jwt Tokens-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on ensuring JWT validation occurs in a context that accounts for network binding. In AdonisJS, use middleware to validate tokens and explicitly verify request metadata. Below are concrete code examples that combine JWT verification with host and origin checks.
Example 1: JWT validation middleware with host/origin verification
import { Exception } from '@poppinss/utils'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { Jwt } from '@ioc:Adonis/Addons/Auth'
export default class JwtWithNetworkValidationMiddleware {
public async handle({ request, response, next }: HttpContextContract) {
const authHeader = request.headers().authorization
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return response.unauthorized({ message: 'Unauthorized: No bearer token provided' })
}
const token = authHeader.split(' ')[1]
const expectedHost = 'api.yourdomain.com'
const allowedOrigins = ['https://yourdomain.com', 'https://app.yourdomain.com']
// Validate Host header to mitigate DNS rebinding
const requestHost = request.host()
if (requestHost !== expectedHost) {
return response.forbidden({ message: 'Forbidden: Host not allowed' })
}
// Validate Origin header if present
const origin = request.headers().origin
if (origin && !allowedOrigins.includes(origin)) {
return response.forbidden({ message: 'Forbidden: Origin not allowed' })
}
try {
const payload = await Jwt.verify(token, 'your_jwt_secret', { type: 'access' })
request.authUser = payload
await next()
} catch (error) {
throw Exception.unauthorized('Invalid or expired token', 'E_INVALID_TOKEN', 401)
}
}
}
Example 2: Route-level protection with CORS and host checks
import Route from '@ioc:Adonis/Core/Route'
Route.group(() => {
Route.get('/admin/users', async ({ request, response }) => {
const host = request.host()
if (host !== 'api.yourdomain.com') {
return response.badRequest({ error: 'Invalid host' })
}
const origin = request.headers().origin
const allowedOrigins = ['https://yourdomain.com']
if (origin && !allowedOrigins.includes(origin)) {
return response.forbidden({ error: 'CORS origin not allowed' })
}
// Proceed with JWT-verified logic
return { users: [] }
}).middleware(['jwt', 'networkValidation'])
}).prefix('api/v1')
Additional measures
- Set CORS policies to strict origins and avoid wildcard (*) in production.
- Validate the Host header in environment-specific configs, especially when behind proxies.
- Use short-lived JWTs and refresh tokens with strict rotation to reduce the window for token replay after rebinding.
- Monitor for unexpected referrer patterns and anomalous token usage across IPs using your dashboard or CLI reports.