MEDIUM insufficient loggingadonisjs

Insufficient Logging in Adonisjs

How Insufficient Logging Manifests in Adonisjs

Insufficient logging in Adonisjs applications creates blind spots that attackers exploit during reconnaissance and post-exploitation phases. Adonisjs's middleware-based architecture and Lucid ORM create specific logging gaps that developers often overlook.

Authentication bypass attempts frequently go unnoticed when developers rely solely on Adonisjs's built-in auth middleware without logging failed authentication attempts. Consider this common pattern:

Route.post('login', async ({ auth, request, response }) => {
  const { email, password } = request.body()
  const login = await auth.attempt(email, password)
  return response.json(login)
})

This code lacks any logging of failed authentication attempts, allowing credential stuffing attacks to proceed undetected. Attackers can hammer the login endpoint without triggering any alerts or visibility into the attack pattern.

SQL injection attempts against Adonisjs's Lucid ORM often produce no meaningful logs. When developers use raw queries without proper logging:

const users = await Database.query()
  .select('*')
  .from('users')
  .where('email', request.input('email'))

Malicious input like ' OR '1'='1 executes silently. Without query logging enabled in config/database.js, these injection attempts leave no trace in application logs.

Middleware execution failures represent another blind spot. Adonisjs's middleware chain can silently fail without proper error handling:

async handle({ request }, next) {
  try {
    await next()
  } catch (error) {
    // No logging here means attackers see no difference between
    // a 500 error and a successful request
  }
}

Without structured logging of middleware errors, attackers cannot distinguish between authentication failures and server errors, making enumeration attacks more effective.

Rate limiting bypass attempts also go unlogged when developers implement custom rate limiting without audit trails:

async handle({ request }, next) {
  const key = request.ip()
  const attempts = await Cache.get(key)
  if (attempts > 5) {
    return response.status(429).send('Too many attempts')
  }
  await Cache.set(key, attempts + 1, '1 hour')
  return await next()
}

This implementation lacks logging of rate limit violations, preventing security teams from identifying coordinated brute force or DoS attempts.

Adonisjs-Specific Detection

Detecting insufficient logging in Adonisjs requires examining both application code and runtime behavior. The framework's convention-over-configuration approach means logging gaps often follow predictable patterns.

Start by examining your config/app.js logging configuration. Adonisjs defaults to console logging, but production deployments need structured logging:

import Logger from '@ioc:Adonis/Core/Logger'

export default class () {
  public async handle({ request }, next) {
    const start = Date.now()
    await next()
    
    Logger.info('Request completed', {
      method: request.method(),
      url: request.url(),
      duration: Date.now() - start,
      userAgent: request.header('user-agent'),
      ip: request.ip()
    })
  }
}

middleBrick's black-box scanning can identify logging deficiencies by analyzing API responses and behavior patterns. The scanner detects when authentication failures return generic error messages without rate limiting or when SQL injection attempts produce inconsistent error responses.

middleBrick specifically tests for:

  • Authentication endpoint response consistency under rapid requests
  • Database error message leakage patterns
  • Middleware error handling visibility
  • Rate limiting implementation effectiveness

The scanner's Input Validation check examines how your Adonisjs application handles malformed input and whether error responses reveal system information. For applications using Lucid ORM, middleBrick tests for SQL injection vulnerabilities by injecting payloads and analyzing response patterns.

middleBrick's Authentication check specifically targets Adonisjs auth implementations, testing for:

// What middleBrick tests for:
// - Consistent timing in auth failures
// - Rate limiting on auth endpoints
// - Information leakage in auth errors
// - Session fixation vulnerabilities

The scanner also examines your OpenAPI/Swagger specification if available, cross-referencing documented endpoints with actual runtime behavior to identify discrepancies that suggest inadequate logging or monitoring.

Adonisjs-Specific Remediation

Remediating insufficient logging in Adonisjs requires implementing comprehensive logging across all security-sensitive operations. Adonisjs's TypeScript-first architecture makes it straightforward to add type-safe logging throughout your application.

Implement structured logging for authentication events:

import Logger from '@ioc:Adonis/Core/Logger'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class AuthLoggerMiddleware {
  public async handle(
    { request, auth }: HttpContextContract,
    next: () => Promise
  ) {
    const ip = request.ip()
    const userAgent = request.header('user-agent')
    
    try {
      await next()
      
      if (auth.isAuthenticated) {
        const user = auth.user!
        Logger.info('Authentication successful', {
          userId: user.id,
          email: user.email,
          ip,
          userAgent,
          endpoint: request.url()
        })
      }
    } catch (error) {
      Logger.warn('Authentication failed', {
        error: error.message,
        ip,
        userAgent,
        endpoint: request.url(),
        timestamp: new Date().toISOString()
      })
      throw error
    }
  }
}

Add this middleware globally in start/kernel.ts to ensure all authentication attempts are logged.

For database operations, enable query logging in config/database.js:

import Logger from '@ioc:Adonis/Core/Logger'

export default {
  connections: {
    pg: {
      client: 'postgresql',
      connection: process.env.DB_CONNECTION_STRING,
      debug: process.env.NODE_ENV === 'development',
      logQuery: process.env.NODE_ENV !== 'test',
      log: (query) => {
        Logger.debug('Database query executed', {
          sql: query.sql,
          bindings: query.bindings,
          time: query.time,
          connection: query.connection,
          file: query.file,
          line: query.line
        })
      }
    }
  }
}

Implement comprehensive error handling with structured logging:

import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
import Logger from '@ioc:Adonis/Core/Logger'

export default class ExceptionHandler extends HttpExceptionHandler {
  constructor() {
    super(Logger)
  }

  public async handle(error, { response }) {
    Logger.error('Unhandled exception', {
      message: error.message,
      stack: error.stack,
      code: error.code,
      status: error.status || 500,
      timestamp: new Date().toISOString()
    })

    if (error.status === 404) {
      return response.status(404).json({
        error: 'Resource not found'
      })
    }

    if (error.status === 401 || error.status === 403) {
      return response.status(error.status).json({
        error: 'Unauthorized'
      })
    }

    return response.status(error.status || 500).json({
      error: 'Internal server error'
    })
  }
}

Enable comprehensive audit logging for sensitive operations:

import Logger from '@ioc:Adonis/Core/Logger'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class AuditLoggerMiddleware {
  public async handle({ request, auth }: HttpContextContract, next: () => Promise) {
    const start = Date.now()
    await next()
    
    const sensitivePaths = ['/admin', '/users', '/payments']
    if (sensitivePaths.some(path => request.url().startsWith(path))) {
      Logger.audit('Sensitive endpoint accessed', {
        method: request.method(),
        url: request.url(),
        userId: auth.user?.id,
        ip: request.ip(),
        userAgent: request.header('user-agent'),
        duration: Date.now() - start
      })
    }
  }
}

Configure LogDNA or similar logging services in config/logger.ts for centralized log aggregation:

import Logger from '@ioc:Adonis/Core/Logger'

export default class LogDNAProvider extends Logger {
  public async log(level, message, meta = {}) {
    const payload = {
      ...meta,
      level,
      message,
      timestamp: new Date().toISOString(),
      app: 'adonis-api',
      env: process.env.NODE_ENV
    }

    // Send to LogDNA or similar service
    await fetch('https://logs.logdna.com/logs/ingest', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    })
  }
}

Frequently Asked Questions

How does middleBrick detect insufficient logging in Adonisjs applications?

middleBrick uses black-box scanning to identify logging gaps by analyzing API response patterns and behavior. The scanner tests authentication endpoints for consistent error responses, examines database query handling for information leakage, and evaluates rate limiting effectiveness. For Adonisjs applications, middleBrick specifically looks for generic error messages that don't vary between authentication failures and server errors, indicating missing audit trails. The scanner also tests for SQL injection vulnerabilities by injecting payloads and analyzing whether responses reveal system information or show inconsistent behavior that suggests inadequate logging of database operations.

What's the difference between regular logging and security audit logging in Adonisjs?

Regular application logging in Adonisjs typically records general operational information like request processing, database queries, and application errors. Security audit logging specifically tracks security-sensitive events that require long-term retention and monitoring: authentication successes and failures, access to sensitive endpoints, data modifications, privilege changes, and configuration changes. Audit logs need to be tamper-evident, often stored separately from application logs, and retained for compliance periods (typically 1-7 years). In Adonisjs, audit logging requires dedicated middleware that captures user identity, IP addresses, timestamps, and action details for events like login attempts, admin panel access, and payment processing operations.