HIGH CWE-125 Memory Safety

CWE-125 in APIs

CWE ID
CWE-125
Category
Input Validation
Severity
HIGH
Short Name
OOB Read

What is CWE-125?

CWE-125, or Out-of-Bounds Read, occurs when an application reads data from outside the intended buffer boundaries. This weakness allows attackers to read sensitive memory contents that should not be accessible, potentially exposing passwords, cryptographic keys, or other confidential information. The vulnerability arises when an application calculates an incorrect buffer size or uses an invalid index to access memory.

In memory-managed languages like C and C++, this weakness is particularly dangerous because it can expose arbitrary memory contents. An attacker might leverage this to bypass security mechanisms, extract sensitive data, or even influence application behavior by reading uninitialized or corrupted memory regions.

CWE-125 in API Contexts

In API development, CWE-125 manifests in several specific ways. One common scenario involves array index validation failures. Consider an API endpoint that accepts pagination parameters:

app.get('/api/users', (req, res) => {
  const page = parseInt(req.query.page) || 0;
  const limit = parseInt(req.query.limit) || 10;
  
  const users = await db.query('SELECT * FROM users LIMIT ? OFFSET ?', [limit, page * limit]);
  res.json(users);
});

If the database query returns fewer results than requested, the API might still attempt to access array indices that don't exist, especially when processing results in memory. This could expose uninitialized memory or previous request data.

Another API-specific manifestation occurs with JSON parsing. When an API parses incoming JSON requests, improper validation of array bounds can lead to out-of-bounds reads:

const data = JSON.parse(req.body);
const items = data.items || [];
for (let i = 0; i <= items.length; i++) { // <= should be <
  processItem(items[i]); // items[items.length] is out of bounds
}

Buffer over-reads also occur when APIs handle binary data or file uploads without proper size validation. An attacker could craft requests with manipulated content-length headers or oversized payloads to trigger out-of-bounds reads during processing.

Detection

Detecting CWE-125 requires both static analysis and dynamic testing. Static analysis tools can identify potential buffer boundary violations by examining code paths and data flow. Look for patterns like array access without bounds checking, pointer arithmetic without validation, or unsafe string operations.

Dynamic testing involves sending crafted requests to API endpoints to trigger potential out-of-bounds conditions. This includes testing with boundary values, negative indices, extremely large numbers, and unexpected data types. Tools like fuzzers can automatically generate these test cases.

middleBrick includes CWE-125 detection in its comprehensive API security scanning. The scanner tests for out-of-bounds conditions by sending boundary-testing requests to your API endpoints. For example, it will test pagination parameters with negative values, extremely large numbers, and non-numeric inputs to identify potential array index validation failures.

The scanner also examines your OpenAPI/Swagger specifications to identify parameters that should have bounds validation but lack proper constraints. If your spec defines a numeric parameter without minimum/maximum values, middleBrick flags this as a potential CWE-125 risk.

During scanning, middleBrick runs 12 parallel security checks including input validation testing that specifically targets boundary condition vulnerabilities. The scanner attempts to access array indices beyond valid ranges and monitors for error responses that might indicate memory access violations or information leakage.

Remediation

Fixing CWE-125 requires implementing proper bounds checking and input validation throughout your API code. Here are concrete remediation strategies with code examples:

1. Array Index Validation

function getSafeItem(array, index) {
  if (!Array.isArray(array)) {
    throw new Error('Expected array');
  }
  if (!Number.isInteger(index) || index < 0 || index >= array.length) {
    throw new Error('Index out of bounds');
  }
  return array[index];
}

// Usage in API endpoint
app.get('/api/items/:index', (req, res) => {
  const index = parseInt(req.params.index);
  const item = getSafeItem(items, index);
  res.json(item);
});

2. Pagination with Bounds Checking

app.get('/api/resources', (req, res) => {
  const page = Math.max(0, parseInt(req.query.page) || 0);
  const limit = Math.min(100, Math.max(1, parseInt(req.query.limit) || 10));
  
  const offset = page * limit;
  const resources = await db.query(
    'SELECT * FROM resources LIMIT ? OFFSET ?', 
    [limit, offset]
  );
  
  if (resources.length < limit && page > 0) {
    return res.status(404).json({ 
      error: 'Page out of range' 
    });
  }
  
  res.json({
    page,
    limit,
    total: resources.length,
    data: resources
  });
});

3. JSON Array Validation

app.post('/api/process', (req, res) => {
  const { items } = req.body;
  
  if (!Array.isArray(items)) {
    return res.status(400).json({ 
      error: 'Expected array for items' 
    });
  }
  
  if (items.length > 1000) {
    return res.status(400).json({ 
      error: 'Items array too large' 
    });
  }
  
  const results = [];
  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    if (typeof item !== 'object' || item === null) {
      return res.status(400).json({ 
        error: `Invalid item at index ${i}` 
      });
    }
    results.push(processItem(item));
  }
  
  res.json(results);
});

4. Buffer Size Validation for Binary Data

app.post('/api/upload', (req, res) => {
  const maxFileSize = 1024 * 1024; // 1MB
  
  if (req.headers['content-length'] > maxFileSize) {
    return res.status(413).json({ 
      error: 'File too large' 
    });
  }
  
  let buffer = Buffer.alloc(0);
  req.on('data', chunk => {
    if (buffer.length + chunk.length > maxFileSize) {
      return res.status(413).json({ 
        error: 'File too large' 
      });
    }
    buffer = Buffer.concat([buffer, chunk]);
  });
  
  req.on('end', () => {
    // Process buffer safely
    processBuffer(buffer);
    res.json({ success: true });
  });
});

5. Type Safety and Input Sanitization

function safeParseInt(value, defaultValue = 0) {
  const num = parseInt(value);
  return Number.isNaN(num) ? defaultValue : num;
}

function validateBounds(value, min, max) {
  const num = safeParseInt(value);
  return Math.min(max, Math.max(min, num));
}

// Usage
app.get('/api/search', (req, res) => {
  const page = validateBounds(req.query.page, 0, 1000);
  const limit = validateBounds(req.query.limit, 1, 100);
  
  // Safe to use without out-of-bounds risk
  const results = await searchDatabase(page, limit);
  res.json(results);
});

Frequently Asked Questions

How does CWE-125 differ from CWE-119 (Improper Restriction of Operations within the Bounds of a Memory Buffer)?
CWE-125 specifically refers to out-of-bounds reads, where data is read from outside allocated memory. CWE-119 is broader, covering any improper restriction of memory buffer operations, including both reads and writes. CWE-125 is a subset of CWE-119 focused on read operations that can leak sensitive information.
Can CWE-125 lead to remote code execution?
While CWE-125 primarily causes information disclosure, it can potentially lead to remote code execution in specific scenarios. If an attacker can read sensitive memory contents like function pointers or return addresses, they might combine this with other vulnerabilities like buffer overflows to achieve code execution. However, the direct impact is usually information disclosure rather than immediate code execution.