HIGH jwt misconfigurationadonisjs

Jwt Misconfiguration in Adonisjs

How Jwt Misconfiguration Manifests in Adonisjs

Jwt misconfiguration in Adonisjs applications typically emerges through several framework-specific patterns that developers encounter when implementing authentication. The most common manifestation occurs in the auth configuration file, where developers might set weak signing algorithms or expose sensitive configuration values.

A critical vulnerability appears when Adonisjs applications use HS256 with weak secrets. Consider this problematic configuration:

// config/auth.js (vulnerable)
module.exports = { jwt: { algorithm: 'HS256', secret: process.env.JWT_SECRET || 'default-secret-here', expiresIn: '30d' } }

The fallback secret 'default-secret-here' creates an immediate attack vector. An attacker can easily decode and forge tokens since the secret is publicly documented in the codebase or environment defaults.

Another Adonisjs-specific issue involves improper middleware configuration. Developers often apply authentication middleware globally without considering the security implications:

// start/kernel.js (problematic)
const globalMiddleware = [ 'Adonis/Middleware/Auth' ]

This configuration forces authentication on every route, including health checks and public API endpoints, creating unnecessary attack surface and potential denial-of-service scenarios.

Token leakage through Adonisjs's response handling represents another critical vulnerability. When developers forget to clear authentication state or improperly handle token refresh:

// app/Controllers/Http/AuthController.js (vulnerable)
class AuthController { async refresh({ auth }) { const token = await auth.generate(auth.user) return { token: token.token, user: auth.user } } }

This code returns the full token object in responses, potentially exposing it through browser developer tools, logs, or client-side storage.

Adonisjs's Lucid ORM integration can also introduce JWT vulnerabilities when developers don't properly scope database queries. An attacker might exploit token validation bypasses:

// app/Controllers/Http/UserController.js (vulnerable)
async show({ auth, params }) { const user = await User.find(params.id) // Missing authorization check return user }

Without verifying that auth.user.id matches params.id, this creates a classic BOLA (Broken Object Level Authorization) vulnerability that works in conjunction with JWT misconfiguration.

Finally, Adonisjs applications often mishandle token revocation. Without proper token blacklisting or rotation mechanisms:

// Missing token revocation logic
async logout({ auth }) {
  // No token invalidation
  return { message: 'Logged out' }
}

Stolen tokens remain valid until expiration, giving attackers extended access windows even after users believe they've logged out.

Adonisjs-Specific Detection

Detecting JWT misconfiguration in Adonisjs requires examining both the framework's configuration files and runtime behavior. The first step involves scanning the auth configuration:

// Automated detection script
const fs = require('fs');
const path = require('path');

function detectJwtMisconfiguration(configPath) {
  if (!fs.existsSync(configPath)) {
    return 'Auth config not found';
  }

  const config = require(configPath);
  const issues = [];

  // Check for weak secrets
  if (config.jwt.secret.includes('default') || config.jwt.secret.length < 32) {
    issues.push('Weak JWT secret detected');
  }

  // Check for insecure algorithms
  if (config.jwt.algorithm !== 'HS256' && config.jwt.algorithm !== 'RS256') {
    issues.push(`Uncommon algorithm: ${config.jwt.algorithm}`);
  }

  // Check for excessive expiration
  const expiration = parseInt(config.jwt.expiresIn);
  if (expiration > 86400) { // 24 hours
    issues.push('JWT expiration exceeds 24 hours');
  }

  return issues;
}

console.log(detectJwtMisconfiguration('./config/auth.js'));

Beyond static analysis, runtime detection requires examining middleware application patterns. A script can analyze the kernel configuration:

function detectGlobalAuthMiddleware(kernelPath) {
  const kernel = require(kernelPath);
  const globalMiddleware = kernel.globalMiddleware || [];
  
  if (globalMiddleware.includes('Adonis/Middleware/Auth')) {
    return 'Global auth middleware applied - potential overblocking';
  }
  return 'Auth middleware configuration appears safe';
}

For comprehensive detection, middleBrick's API security scanner specifically targets Adonisjs JWT vulnerabilities through black-box testing. The scanner attempts to:

  • Extract JWT secrets from configuration files and environment variables
  • Test for weak algorithm implementations
  • Verify proper token validation across endpoints
  • Check for exposed token endpoints
  • Validate authorization checks are properly implemented

middleBrick's scanning process for Adonisjs applications includes 12 parallel security checks that specifically examine JWT implementation patterns. The scanner tests unauthenticated attack surfaces, attempting to bypass authentication or extract sensitive information without requiring credentials.

The scanner's OpenAPI analysis capability is particularly valuable for Adonisjs applications, as it can cross-reference your API specifications with actual runtime behavior, identifying discrepancies between documented and implemented security controls.

Adonisjs-Specific Remediation

Remediating JWT misconfiguration in Adonisjs requires both configuration changes and code-level fixes. Start with the auth configuration:

// config/auth.js (secure configuration)
module.exports = { jwt: { algorithm: 'HS256', secret: Env.get('JWT_SECRET'), expiresIn: '2h', // Reduced from 30d refreshable: true, renew: true } }

Key improvements: removed fallback secrets, reduced expiration to 2 hours, enabled refreshable tokens with automatic renewal. Store the JWT_SECRET in environment variables with sufficient length (minimum 32 characters of random data).

Implement proper token handling in controllers:

// app/Controllers/Http/AuthController.js (secure)
class AuthController {
  async login({ auth, request }) {
    const { email, password } = request.all();
    const token = await auth.attempt(email, password);
    
    // Return only necessary data
    return {
      type: token.type,
      token: token.token,
      refreshToken: token.refreshToken,
      expiresIn: token.expiresIn
    };
  }

  async refresh({ auth }) {
    const token = await auth.generate(auth.user);
    return {
      token: token.token,
      refreshToken: token.refreshToken,
      expiresIn: token.expiresIn
    };
  }

  async logout({ auth }) {
    await auth.revoke();
    return { message: 'Logged out successfully' };
  }
}

Notice the use of auth.revoke() for proper token invalidation and selective data exposure in responses.

Add authorization middleware to prevent BOLA vulnerabilities:

// app/Middleware/AuthorizeUser.js
'use strict';

const { HttpContextContract } = require('@adonisjs/core/http')

class AuthorizeUser {
  async handle({ auth, params, response }, next) {
    if (auth.user.id !== Number(params.id)) {
      return response.status(403).send({ error: 'Forbidden' });
    }
    await next();
  }
}

module.exports = AuthorizeUser;

Apply this middleware to user-specific routes:

// start/routes.js
Route.get('users/:id', 'UserController.show')
  .middleware('auth')
  .middleware('authorizeUser');

For enhanced security, implement token rotation and refresh mechanisms:

// app/Services/JwtService.js
'use strict';

const Env = use('Env');

class JwtService {
  async refreshAccessToken(refreshToken) {
    const verified = await this.verifyToken(refreshToken);
    
    if (!verified || verified.type !== 'refresh') {
      throw new Error('Invalid refresh token');
    }
    
    const user = await User.find(verified.uid);
    return await this.generateTokens(user);
  }

  async generateTokens(user) {
    const auth = use('Auth')
    const token = await auth.withRefreshToken().generate(user);
    
    return {
      accessToken: token.token,
      refreshToken: token.refreshToken,
      expiresIn: token.expiresIn
    };
  }

  async verifyToken(token) {
    return use('Token').verify(token, Env.get('JWT_SECRET'));
  }
}

module.exports = JwtService;

Finally, integrate middleBrick's scanning into your development workflow to catch JWT misconfigurations early:

# Install middleBrick CLI
npm install -g middlebrick

# Scan your Adonisjs API
middlebrick scan http://localhost:3333/api

# In CI/CD pipeline
middlebrick scan https://staging.example.com/api --fail-below B

This comprehensive approach addresses configuration weaknesses, implementation flaws, and provides continuous monitoring through middleBrick's scanning capabilities.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Why does Adonisjs use JWT by default instead of sessions?
Adonisjs uses JWT by default because it's stateless and scales better for modern API architectures. JWT tokens don't require server-side session storage, making them ideal for distributed systems, mobile applications, and microservices where maintaining session state across multiple servers becomes complex. The framework's auth system is designed to work seamlessly with JSON APIs rather than traditional server-rendered applications.
How does middleBrick detect JWT misconfiguration without credentials?
middleBrick performs black-box scanning by examining publicly accessible endpoints and configuration files. It tests for weak secrets by attempting common default values, analyzes token validation logic by observing error responses, and checks for exposed endpoints that shouldn't require authentication. The scanner also examines OpenAPI specifications if available and tests the actual runtime behavior against documented security controls.