MEDIUM log injectionbasic auth

Log Injection with Basic Auth

How Log Injection Manifests in Basic Auth

Log injection in Basic Auth systems occurs when an attacker crafts credentials that exploit how authentication logs are processed. The most common attack vector involves the username field, where special characters can break out of intended log contexts.

Consider a typical Basic Auth implementation:

const http = require('http');
const auth = require('basic-auth');

const server = http.createServer((req, res) => {
  const credentials = auth(req);
  
  if (!credentials) {
    res.statusCode = 401;
    res.setHeader('WWW-Authenticate', 'Basic realm="example"');
    res.end('Unauthorized');
    return;
  }
  
  const { name: username, pass: password } = credentials;
  
  // Vulnerable logging
  console.log(`Auth attempt: user=${username}, password=${password}`);
  
  if (username === 'admin' && password === 'secret') {
    res.end('Welcome admin');
  } else {
    res.end('Invalid credentials');
  }
});

The vulnerability appears in the logging statement. An attacker can submit a username like:

admin

Basic Auth-Specific Detection

Detecting log injection in Basic Auth systems requires examining both the authentication code and the logging infrastructure. Here's how to identify this vulnerability:

Code Review Checklist:

  • Look for direct string interpolation in log statements that include username or password values
  • Check if log messages use structured formats (JSON, key-value pairs) that could be manipulated
  • Verify if log sanitization occurs before authentication logging
  • Examine if logs are written to files or systems that parse structured data

Automated Scanning with middleBrick:

middleBrick's black-box scanning approach can detect log injection vulnerabilities in Basic Auth endpoints without requiring source code access. The scanner tests for:

  • Special character handling in username fields
  • Structured data injection attempts
  • Newline and control character processing
  • Log format manipulation

The scanner attempts payloads like:

username=test

Basic Auth-Specific Remediation

Fixing log injection in Basic Auth systems involves proper input sanitization and secure logging practices. Here are specific remediation strategies:

1. Sanitize Log Inputs:

const http = require('http');
const auth = require('basic-auth');

function sanitizeLogInput(input) {
  return input
    .replace(/
/g, '\n')
    .replace(/
/g, '\r')
    .replace(/	/g, '\t')
    .replace(/,/g, ', ')
    .replace(/:/g, ': ');
}

const server = http.createServer((req, res) => {
  const credentials = auth(req);
  
  if (!credentials) {
    res.statusCode = 401;
    res.setHeader('WWW-Authenticate', 'Basic realm="example"');
    res.end('Unauthorized');
    return;
  }
  
  const { name: username, pass: password } = credentials;
  
  // Secure logging with sanitization
  console.log(`Auth attempt: user=${sanitizeLogInput(username)}, 
              password=[FILTERED], success=false`);
  
  if (username === 'admin' && password === 'secret') {
    console.log(`Auth successful: user=${sanitizeLogInput(username)}`);
    res.end('Welcome admin');
  } else {
    res.end('Invalid credentials');
  }
});

2. Use Structured Logging with Validation:

const winston = require('winston');

const logger = winston.createLogger({
  format: winston.format.json(),
  transports: [new winston.transports.Console()]
});

function validateAuthLogData(data) {
  const allowedKeys = ['username', 'ip', 'timestamp', 'success'];
  return Object.keys(data).every(key => allowedKeys.includes(key));
}

const server = http.createServer((req, res) => {
  const credentials = auth(req);
  
  if (!credentials) {
    res.statusCode = 401;
    res.end('Unauthorized');
    return;
  }
  
  const { name: username } = credentials;
  const authLogData = {
    username: sanitizeLogInput(username),
    ip: req.connection.remoteAddress,
    timestamp: new Date().toISOString(),
    success: false
  };
  
  if (validateAuthLogData(authLogData)) {
    logger.info('Authentication attempt', authLogData);
  }
  
  if (username === 'admin') {
    logger.info('Authentication successful', { ...authLogData, success: true });
    res.end('Welcome admin');
  } else {
    res.end('Invalid credentials');
  }
});

3. Implement Rate Limiting and Monitoring:

const rateLimit = require('express-rate-limit');

const authAttemptLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests
  message: 'Too many authentication attempts',
  keyGenerator: req => req.connection.remoteAddress
});

// Apply rate limiting to Basic Auth endpoints
app.use('/api/auth', authAttemptLimiter);

4. Use Framework-Specific Security Features:

With Express and Passport:

const express = require('express');
const passport = require('passport');
const BasicStrategy = require('passport-http').BasicStrategy;

passport.use(new BasicStrategy((username, password, done) => {
  // Validate credentials
  if (username === 'admin' && password === 'secret') {
    return done(null, { id: 1 });
  }
  return done(null, false);
}));

app.use((req, res, next) => {
  // Log authentication attempts securely
  const logData = {
    username: sanitizeLogInput(req.body?.username || ''),
    ip: req.ip,
    timestamp: new Date().toISOString()
  };
  
  logger.info('Auth attempt', logData);
  next();
});

These remediation strategies ensure that Basic Auth implementations remain secure against log injection attacks while maintaining proper audit trails for legitimate security monitoring.

Frequently Asked Questions

How does log injection differ from regular injection attacks?
Log injection specifically targets how authentication events are recorded, allowing attackers to manipulate audit trails and security monitoring. Unlike SQL injection or XSS that affect application functionality, log injection creates misleading security records that can hide unauthorized access or trigger false alerts.
Can middleBrick detect log injection in Basic Auth endpoints?