HIGH broken authenticationadonisjs

Broken Authentication in Adonisjs

How Broken Authentication Manifests in Adonisjs

Broken authentication in Adonisjs applications typically occurs through several framework-specific patterns. The most common vulnerability appears in session management where developers fail to properly configure the session middleware or use default settings that aren't suitable for production environments.

A critical Adonisjs-specific issue arises when using the default session driver without proper encryption. Consider this vulnerable configuration:

// start/kernel.js - vulnerable configuration
const namedMiddleware = {
  auth: 'Adonis/Middleware/Auth',
  session: 'Adonis/Middleware/Session'
}

// Using default session settings without encryption
const session = {
  driver: 'cookie',
  secret: process.env.SESSION_SECRET || 'default-secret', // <--- CRITICAL VULNERABILITY
  httpOnly: true,
  maxAge: 24 * 60 * 60 * 1000
}

The default 'default-secret' allows session hijacking since the session data is stored in plaintext cookies. An attacker who obtains a user's cookie can immediately impersonate them without needing credentials.

Another Adonisjs-specific pattern involves improper use of the auth middleware. Developers often forget to protect routes or misconfigure authentication guards:

// routes.js - vulnerable route protection
Route.get('/admin/dashboard', ({ auth }) => {
  // No guard specified - uses default which might be incorrect
  if (auth.user) {
    return view.render('admin.dashboard')
  }
  return 'Unauthorized'
}).middleware('auth')

This code appears secure but fails if the default guard isn't properly configured or if multiple guards exist. An attacker can exploit this by crafting requests that bypass authentication checks.

Password handling in Adonisjs applications often reveals broken authentication through weak hashing or missing rate limiting. The framework's built-in Hash provider makes it easy to hash passwords correctly, but developers sometimes bypass it:

// Vulnerable password storage
const User = use('App/Models/User')

class UserController {
  async register({ request }) {
    const userData = request.only(['username', 'password'])
    
    // CRITICAL: Storing plaintext passwords
    const user = await User.create({
      username: userData.username,
      password: userData.password // Should use Hash.make()
    })
    
    return user
  }
}

This code stores passwords in plaintext, making database breaches catastrophic. Even with the Hash provider available, developers might forget to use it or use insufficient iterations.

Token-based authentication in Adonisjs APIs often suffers from broken authentication when JWT secrets are hardcoded or weak:

// config/auth.js - vulnerable JWT configuration
module.exports = {
  authenticator: 'jwt',
  secret: 'super-secret-jwt-key', // Hardcoded secret - easily compromised
  options: {
    expiresIn: '1 days',
    algorithm: 'HS256'
  }
}

Hardcoded secrets mean that if source code is exposed through any means, all tokens become immediately forgeable. This is particularly dangerous in open-source projects or when code is shared between environments.

Session fixation attacks target Adonisjs applications when developers don't regenerate session IDs after authentication. The framework provides auth.attempt() which should handle this, but custom implementations often miss it:

// Vulnerable login implementation
class AuthController {
  async login({ auth, request, response }) {
    const { email, password } = request.all()
    
    // CRITICAL: No session fixation protection
    const user = await User.query().where('email', email).first()
    if (user && await Hash.verify(password, user.password)) {
      await auth.generate(user) // Doesn't regenerate session ID
      return response.redirect('/dashboard')
    }
    
    return response.badRequest('Invalid credentials')
  }
}

This implementation allows session fixation because the session ID remains the same before and after authentication. An attacker can fixate a session ID, trick a victim into authenticating with it, and then use the same session ID to access the account.

Adonisjs-Specific Detection

Detecting broken authentication in Adonisjs requires examining both configuration files and runtime behavior. Start with configuration analysis:

// Check for vulnerable session configuration
const sessionConfig = require('../config/session')

if (sessionConfig.secret === 'default-secret') {
  console.warn('CRITICAL: Using default session secret')
}

if (sessionConfig.driver === 'cookie' && !sessionConfig.encryption) {
  console.warn('WARNING: Cookie sessions not encrypted')
}

Run this check during application startup to catch configuration issues early. For JWT tokens, validate secret strength:

// Check JWT secret strength
const authConfig = require('../config/auth')
const crypto = require('crypto')

function isWeakSecret(secret) {
  // Check if secret is default or too short
  const weakSecrets = ['super-secret', 'jwt-secret', 'your-secret-here']
  if (weakSecrets.includes(secret)) return true
  if (secret.length < 32) return true // Too short for HS256
  
  // Check entropy - weak secrets often have low entropy
  const hash = crypto.createHash('sha256').update(secret).digest('hex')
  const entropy = hash.split('').reduce((sum, char) => {
    return sum + char.charCodeAt(0)
  }, 0) / hash.length
  
  return entropy < 50 // Arbitrary threshold for weak secrets
}

if (isWeakSecret(authConfig.secret)) {
  console.error('CRITICAL: Weak JWT secret detected')
}

For runtime detection, implement middleware that checks authentication patterns:

// middleware/auth-check.js
const User = use('App/Models/User')

class AuthCheck {
  async handle({ auth, request, response }, next) {
    // Check if auth is being used without proper guard specification
    if (!auth.authenticator && request.url().startsWith('/api')) {
      console.warn(`Missing authenticator on API route: ${request.url()}`)
    }
    
    // Check for session fixation vulnerability
    const isLogin = request.url() === '/login' && request.method() === 'POST'
    if (isLogin) {
      const oldSessionId = request.cookie('adonis-session')
      await next()
      const newSessionId = response.lazyBody._content.cookie['adonis-session']
      
      if (oldSessionId === newSessionId) {
        console.error('Session fixation vulnerability: session ID not regenerated')
      }
    } else {
      await next()
    }
  }
}

module.exports = AuthCheck

Automated scanning with middleBrick provides comprehensive detection without modifying your codebase. The CLI tool scans your running Adonisjs application:

npm install -g middlebrick

# Scan your Adonisjs API
middlebrick scan https://yourapp.com/api --output json

# Output shows authentication-specific findings:
{
  "authentication": {
    "score": 45,
    "severity": "high",
    "findings": [
      {
        "title": "Weak session secret detected",
        "severity": "high",
        "remediation": "Use a 32+ character random secret from environment variables",
        "path": "config/session.js"
      }
    ]
  }
}

The middleBrick dashboard provides continuous monitoring of authentication vulnerabilities across your Adonisjs applications. You can track authentication score trends and receive alerts when configurations become insecure.

Adonisjs-Specific Remediation

Remediating broken authentication in Adonisjs requires both configuration changes and code updates. Start with secure session configuration:

// config/session.js - secure configuration
module.exports = {
  driver: 'redis', // Use server-side storage instead of cookies
  connection: 'redis',
  secret: Env.get('SESSION_SECRET'), // Never hardcode secrets
  httpOnly: true,
  maxAge: 24 * 60 * 60 * 1000,
  secure: true, // Only send over HTTPS
  sameSite: 'strict',
  encryption: true // Encrypt session data
}

// Generate secure secret
// node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

For JWT authentication, use environment-based secrets with proper validation:

// config/auth.js - secure JWT configuration
module.exports = {
  authenticator: 'jwt',
  secret: Env.get('JWT_SECRET'),
  options: {
    expiresIn: '1h', // Shorter expiration for better security
    algorithm: 'HS256',
    issuer: 'your-app-name',
    audience: 'your-api-users'
  }
}

// Generate secure JWT secret
// node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"

Implement proper password hashing with adequate iterations:

// app/Models/User.js
const User = use('Model')
const Hash = use('Hash')

User.addHook('beforeSave', async (userInstance) => {
  if (userInstance.dirty.password) {
    // Use 12+ rounds for bcrypt - higher is better but slower
    userInstance.password = await Hash.make(userInstance.password, 12)
  }
})

module.exports = User

Protect routes with proper guard specification:

// routes.js - secure route protection
Route.group(() => {
  Route.get('/admin/dashboard', 'AdminController.dashboard')
  Route.post('/admin/users', 'AdminController.createUser')
})
  .prefix('admin')
  .middleware(['auth:admin']) // Specify guard explicitly

Fix session fixation by regenerating session IDs after authentication:

// app/Controllers/Http/AuthController.js
const User = use('App/Models/User')
const Antl = use('Antl')

class AuthController {
  async login({ auth, request, response, session }) {
    const { email, password } = request.all()
    
    // Use auth.attempt() which handles session fixation
    try {
      await auth.attempt(email, password)
      
      // Regenerate session ID manually as additional protection
      const oldSessionId = session.id()
      await session.regenerate()
      const newSessionId = session.id()
      
      if (oldSessionId === newSessionId) {
        console.warn('Session regeneration failed')
      }
      
      return response.redirect('/dashboard')
    } catch (error) {
      return response.badRequest({ error: Antl.forLocale('en').formatMessage('auth.invalid') })
    }
  }
}

module.exports = AuthController

Implement rate limiting to prevent credential stuffing attacks:

// start/kernel.js - add rate limiting
const namedMiddleware = {
  auth: 'Adonis/Middleware/Auth',
  session: 'Adonis/Middleware/Session',
  'throttle': 'Adonis/Middleware/Throttle',
  'verifyCSRFToken': 'Adonis/Middleware/CsrfToken'
}

// Add to routes.js
Route.post('/login', 'AuthController.login')
  .middleware(['throttle:100,5']) // 100 requests per 5 minutes

Add authentication monitoring middleware to detect suspicious patterns:

// middleware/AuthenticationMonitor.js
const moment = require('moment')

class AuthenticationMonitor {
  async handle({ auth, request, response }, next) {
    const start = Date.now()
    await next()
    
    const duration = Date.now() - start
    const ip = request.ip()
    const url = request.url()
    
    // Log authentication attempts for monitoring
    if (url.includes('login') || url.includes('auth')) {
      console.log(`Auth attempt: ${ip} - ${url} - ${duration}ms - ${auth.user ? 'SUCCESS' : 'FAILURE'}`)
      
      // Check for unusual patterns
      if (duration < 100 && !auth.user) {
        console.warn(`Potential brute force from ${ip}: quick failed attempt`)
      }
    }
  }
}

module.exports = AuthenticationMonitor

Finally, integrate middleBrick into your development workflow for continuous authentication security assessment:

# package.json scripts
{
  "scripts": {
    "start": "adonis serve --dev",
    "scan:auth": "middlebrick scan http://localhost:3333 --category authentication",
    "test": "adonis test && npm run scan:auth"
  }
}

This ensures authentication security is validated with every test run, catching regressions before they reach production.

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

How does Adonisjs's built-in authentication compare to other Node.js frameworks?
Adonisjs provides a more opinionated authentication system than Express.js, with built-in guards, middleware, and session management. Unlike Express which requires manual integration of passport strategies, Adonisjs includes JWT, session, and basic auth out of the box with consistent APIs. The framework's auth provider automatically handles session fixation protection and CSRF tokens, reducing common authentication vulnerabilities. However, this convenience means developers must understand the framework's defaults—Adonisjs's session middleware uses encrypted cookies by default in newer versions, but older applications might still use vulnerable configurations.
Can middleBrick detect authentication vulnerabilities in Adonisjs applications without source code access?
Yes, middleBrick performs black-box scanning that tests your Adonisjs API's runtime behavior without requiring source code. The scanner sends authenticated and unauthenticated requests to test session management, JWT token handling, and route protection. It detects issues like weak session secrets by analyzing cookie encryption, identifies missing authentication middleware by accessing protected endpoints, and tests for session fixation by checking if session IDs change after login. The scanner also analyzes HTTP headers, response codes, and error messages to identify authentication bypass opportunities specific to how Adonisjs handles requests.