HIGH path traversalbasic auth

Path Traversal with Basic Auth

How Path Traversal Manifests in Basic Auth

Path traversal vulnerabilities in Basic Auth contexts occur when authentication mechanisms fail to properly sanitize file paths, allowing attackers to escape intended directories. In Basic Auth implementations, this often manifests through several attack vectors.

The most common pattern involves URL manipulation where attackers append ../ sequences to authenticated endpoints. For example, a Basic Auth-protected endpoint at /api/v1/files/download might be manipulated to /api/v1/files/download/../../../../etc/passwd. Since Basic Auth headers are processed before path validation in many frameworks, the authentication check passes before the path traversal is detected.

Another variant exploits case-insensitive file systems. An attacker might request /api/v1/files/download/Windows/System32/cmd.exe on a Linux server, or /api/v1/files/download/etc/passwd with mixed case variations. Basic Auth implementations that don't normalize paths before validation can be tricked into serving files outside the intended directory.

Directory traversal can also occur through URL encoding attacks. Basic Auth credentials are base64-encoded but URL encoding of the path portion can bypass simple sanitization. An attacker might use %2e%2e%2f (URL-encoded ../) or ..%2f to evade path traversal filters. Since the Basic Auth header is processed separately from the URL path, these attacks can succeed if the server doesn't properly decode and normalize paths before file access.

Basic Auth-specific implementations are particularly vulnerable when using Node.js's fs module without path normalization. Consider this vulnerable pattern:

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

const server = http.createServer((req, res) => {
  const credentials = auth(req);
  if (!credentials || credentials.name !== 'admin' || credentials.pass !== 'secret') {
    res.statusCode = 401;
    res.setHeader('WWW-Authenticate', 'Basic realm="files"');
    res.end('Unauthorized');
    return;
  }
  
  // Vulnerable: no path normalization
  const filePath = `/var/files/${req.url.split('/').pop()}`;
  fs.readFile(filePath, (err, data) => {
    if (err) {
      res.statusCode = 404;
      res.end('File not found');
    } else {
      res.end(data);
    }
  });
});

This code authenticates correctly but fails to validate the requested path. An attacker can access /api/v1/files/download/../../../etc/passwd and bypass the intended file directory.

Another Basic Auth-specific scenario involves default directory indexes. When Basic Auth protects a directory listing endpoint, attackers can use path traversal to navigate to parent directories and discover file structures. For instance, requesting /api/v1/files/../../../../ might reveal directory contents that should remain hidden, even though the Basic Auth credentials are valid.

Windows-specific path traversal attacks also affect Basic Auth implementations. Using .. sequences or \ backslashes can sometimes bypass filters that only check for forward slashes. Basic Auth middleware that doesn't normalize path separators creates opportunities for these attacks.

Time-of-check to time-of-use (TOCTOU) race conditions can occur in Basic Auth contexts when file validation and access are separated. An attacker might authenticate, then quickly manipulate the path between the validation and access phases, exploiting Basic Auth's stateless nature where credentials are re-validated for each request.

Basic Auth-Specific Detection

Detecting path traversal in Basic Auth implementations requires examining both the authentication layer and file access patterns. Several approaches can identify these vulnerabilities.

Static code analysis tools can scan for dangerous patterns in Basic Auth implementations. Look for code that:

  • Uses fs or similar file system modules without path normalization
  • Concatenates user input directly into file paths after Basic Auth validation
  • Doesn't use path.normalize(), path.join(), or path.resolve() when constructing file paths
  • Relies solely on Basic Auth for security without additional path validation

Dynamic testing with tools like middleBrick can automatically detect path traversal vulnerabilities in Basic Auth-protected APIs. The scanner tests for common traversal patterns including:

Test PatternAttack VectorExpected Detection
../ sequencesStandard traversalUnauthorized access to parent directories
URL-encoded %2e%2e%2fEncoding bypassAccess when encoding should be blocked
Mixed case variationsCase sensitivityAccess on case-insensitive systems
Windows-specific \ sequencesPlatform-specificAccess when backslashes are accepted

middleBrick's black-box scanning approach tests the unauthenticated attack surface by submitting these traversal patterns to Basic Auth-protected endpoints and analyzing responses. The scanner checks if authentication is bypassed or if files outside the intended directory are accessible.

Manual testing should include attempting to access known sensitive files through Basic Auth endpoints. Common targets include:

/api/v1/files/download/../../../../etc/passwd
/api/v1/files/download/../../../../windows/win.ini
/api/v1/files/download/../../../../boot.ini
/api/v1/files/download/..%2F..%2F..%2F..%2Fetc%2fpasswd
/api/v1/files/download/..\..\..\..\..\etc\passwd

Monitor the server's response time and error messages. Path traversal often results in different response times or error messages compared to valid requests, which can be detected through timing analysis or error pattern matching.

Log analysis can reveal path traversal attempts. Search for patterns like:

  • Multiple consecutive ../ sequences in URLs
  • Access attempts to system directories (/etc/, /proc/, /boot/)
  • Unusual file extensions or system file requests
  • Encoded path sequences in request logs

Network-level detection can identify path traversal through intrusion detection systems that monitor for suspicious path patterns in HTTP requests, even when Basic Auth headers are present.

Basic Auth-Specific Remediation

Remediating path traversal in Basic Auth implementations requires a defense-in-depth approach that combines authentication, authorization, and input validation. Here are specific code-level fixes for Basic Auth scenarios.

The most critical remediation is path normalization before file access. Always resolve and validate paths against a known base directory:

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

const BASE_DIR = '/var/files';

const server = http.createServer((req, res) => {
  const credentials = auth(req);
  if (!credentials || credentials.name !== 'admin' || credentials.pass !== 'secret') {
    res.statusCode = 401;
    res.setHeader('WWW-Authenticate', 'Basic realm="files"');
    res.end('Unauthorized');
    return;
  }
  
  // Get the requested filename from URL
  const urlParts = req.url.split('/');
  const filename = urlParts.pop() || urlParts.pop(); // handle trailing slash
  
  // Critical: normalize and validate the path
  const filePath = path.normalize(path.join(BASE_DIR, filename));
  
  // Verify the resolved path is within the base directory
  if (!filePath.startsWith(BASE_DIR + path.sep)) {
    res.statusCode = 403;
    res.end('Forbidden');
    return;
  }
  
  // Check if file exists and is accessible
  fs.stat(filePath, (err, stats) => {
    if (err || !stats.isFile()) {
      res.statusCode = 404;
      res.end('File not found');
      return;
    }
    
    // Serve the file
    fs.createReadStream(filePath).pipe(res);
  });
});

This implementation ensures that even if an attacker provides a path with ../ sequences, the normalized path will either stay within the base directory or be rejected.

For Express.js applications with Basic Auth middleware, use a similar approach:

const express = require('express');
const basicAuth = require('express-basic-auth');
const path = require('path');

const app = express();

// Basic Auth middleware
app.use(basicAuth({
  users: { admin: 'secret' },
  challenge: true,
  realm: 'files'
}));

// Secure file download endpoint
app.get('/api/v1/files/download/:filename', (req, res) => {
  const filename = path.basename(req.params.filename); // strip any directory components
  const filePath = path.join(__dirname, 'files', filename);
  
  // Validate the file exists and is within the files directory
  if (!filePath.startsWith(path.join(__dirname, 'files'))) {
    return res.status(403).send('Forbidden');
  }
  
  fs.stat(filePath, (err, stats) => {
    if (err || !stats.isFile()) {
      return res.status(404).send('File not found');
    }
    
    res.download(filePath);
  });
});

Additional security measures include:

  • Whitelist allowed file extensions to prevent executable file access
  • Set file permissions to restrict access to sensitive files
  • Use a chroot jail or container to limit file system access
  • Implement rate limiting to prevent brute-force path traversal attempts

For Python Flask applications with Basic Auth:

from flask import Flask, request, send_from_directory
from functools import wraps
import os

def check_auth(username, password):
    return username == 'admin' and password == 'secret'

def authenticate():
    return 'Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="files"'}

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

app = Flask(__name__)
FILES_DIR = '/var/files'

@app.route('/api/v1/files/download/<path:filename>')
@requires_auth
def download_file(filename):
    # Normalize and validate path
    base_path = os.path.abspath(FILES_DIR)
    requested_path = os.path.abspath(os.path.join(FILES_DIR, filename))
    
    if not requested_path.startswith(base_path):
        return 'Forbidden', 403
    
    if not os.path.isfile(requested_path):
        return 'File not found', 404
    
    return send_from_directory(FILES_DIR, filename, as_attachment=True)

Remember that Basic Auth alone provides only authentication, not authorization or input validation. Always combine it with proper path validation, least privilege file system access, and regular security testing to prevent path traversal vulnerabilities.

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 Basic Auth automatically prevent path traversal attacks?
Basic Auth only handles authentication (verifying who you are), not authorization (what you can access) or input validation. It validates credentials before any request processing, but doesn't examine the requested path or sanitize file access. Path traversal requires separate validation logic to ensure requested paths stay within intended directories.
Can path traversal work even if Basic Auth credentials are invalid?
No, path traversal attacks typically require valid authentication first. Basic Auth rejects unauthorized requests with a 401 status before any path processing occurs. However, once authenticated, the path traversal vulnerability can be exploited. This is why secure coding practices are essential even in authenticated endpoints.