Log Injection in Adonisjs
How Log Injection Manifests in Adonisjs
Log injection in Adonisjs occurs when untrusted user input is directly written to log files without proper sanitization. This creates several security vulnerabilities specific to Adonisjs applications.
The most common pattern involves using console.log() or Adonisjs's Logger within route handlers to debug or track user activity. For example:
Route.post('users', async ({ request, response, logger }) => {
const userData = request.only(['username', 'email', 'password'])
// Vulnerable: Direct log injection
logger.info(`User ${userData.username} created with email ${userData.email}`)
// ... rest of logic
})An attacker could submit a username like admin"; process.exit()//, causing the log to contain malicious content that could be executed if the log is processed by another system.
Adonisjs's Logger service, while powerful, doesn't automatically sanitize input. When using structured logging:
logger.info('User created', {
user: request.input('username'),
email: request.input('email')
})The structured format helps but doesn't prevent injection if the values themselves contain malicious content like newline characters or log formatting sequences.
Another Adonisjs-specific scenario involves logging database query results or error objects that may contain user-controlled data:
try {
const user = await User.findBy('email', email)
logger.info(`Found user: ${user}`) // Could expose sensitive data
} catch (error) {
logger.error(`Database error: ${error.message}`) // May log stack traces with sensitive paths
}Adonisjs's development environment often logs stack traces that include absolute file paths, which can reveal application structure to attackers.
Adonisjs-Specific Detection
Detecting log injection in Adonisjs requires examining both code patterns and runtime behavior. Using middleBrick's API scanner, you can identify vulnerable endpoints by scanning your Adonisjs application's routes.
middleBrick analyzes the unauthenticated attack surface and identifies endpoints that accept user input likely to be logged. It specifically looks for:
- Route handlers that accept parameters without validation
- Direct use of
console.log()orloggerwith request data - Structured logging with unvalidated user input
- Middleware that logs request headers or body content
- Database error logging that might expose stack traces
The scanner tests these endpoints with payloads containing newline characters, log formatting sequences, and other injection patterns. For example, it might submit a username like:
attacker
INFO:root:Malicious log entry
usernameIf your application logs this content directly, middleBrick will flag it as a log injection vulnerability.
Adonisjs developers can also use the built-in logger configuration to detect issues. Check your config/logger.ts for transports that write to files or external services:
import Logger from '@ioc:Adonis/Core/Logger'
export default class LogInjectionDetector {
public static detectInjection(payload: string): boolean {
// Check for newline characters, carriage returns, and log formatting
const injectionPatterns = /[\n\r%]/
return injectionPatterns.test(payload)
}
public static scanRoute(route: Route) {
// Analyze route handlers for logging patterns
const handlerCode = route.handler.toString()
// Look for logger.info, logger.error, console.log patterns
}
}Run this analysis during development to catch potential log injection points before deployment.
Adonisjs-Specific Remediation
Remediating log injection in Adonisjs requires a defense-in-depth approach using the framework's native features. Start by implementing input sanitization in your route handlers:
import { sanitize } from 'sanitize-text'
Route.post('users', async ({ request, response, logger }) => {
const userData = request.only(['username', 'email'])
// Sanitize all user input before logging
const safeUsername = sanitize(userData.username)
const safeEmail = sanitize(userData.email)
logger.info('User created', {
username: safeUsername,
email: safeEmail
})
// Continue with business logic
})The sanitize-text package removes potentially dangerous characters while preserving readability.
Adonisjs's Logger service supports custom formatters that can automatically sanitize log messages. Create a custom formatter in app/Logger/Formatters/SafeFormatter.ts:
import { Formatter } from '@adonisjs/logger'
export class SafeFormatter extends Formatter {
public format(level: string, message: string, meta: any) {
// Sanitize message and metadata
const safeMessage = this.sanitize(message)
const safeMeta = Object.keys(meta).reduce((acc, key) => {
acc[key] = this.sanitize(String(meta[key]))
return acc
}, {})
return super.format(level, safeMessage, safeMeta)
}
private sanitize(input: string): string {
// Remove newlines, carriage returns, and log formatting characters
return input.replace(/[\n\r%]/g, '?')
}
}Configure it in config/logger.ts:
import { SafeFormatter } from 'App/Logger/Formatters/SafeFormatter'
const loggerConfig = {
formatter: new SafeFormatter(),
// ... other config
}For structured logging, use Adonisjs's validation system to ensure log data meets safety requirements:
import { schema, rules } from '@ioc:Adonis/Core/Validator'
const logSchema = schema.create({
username: schema.string.optional({
escape: true,
trim: true
}),
email: schema.string.optional({
escape: true,
trim: true,
format: rules.email()
})
})
Route.post('users', async ({ request, response, logger }) => {
const logData = await request.validate({
schema: logSchema,
data: request.only(['username', 'email'])
})
logger.info('User created', logData)
// Continue with business logic
})This approach ensures only validated, sanitized data reaches your logs.