Skip to content

CWE-787: Out-of-bounds Write

Overview

Out-of-bounds Write occurs when a program writes data beyond the allocated boundaries of a buffer, array, or memory region. This typically happens due to missing bounds checks, incorrect size calculations, or unsafe functions that don't validate write limits.

Risk

Critical: Writing beyond buffer boundaries can corrupt adjacent memory, overwrite critical data structures, crash the application, or enable arbitrary code execution. This is one of the most severe vulnerability classes, often exploited to gain full system control.

Remediation Steps

Core principle: Prevent out-of-bounds writes by enforcing bounds checks and using memory-safe abstractions.

Locate the out-of-bounds write vulnerability in your code

  • Identify the vulnerable buffer: Check your scan results for the specific buffer or array being written beyond bounds (char arrays, memory buffers, dynamic arrays)
  • Find the write operation: Locate the sink where out-of-bounds write occurs (strcpy, memcpy, sprintf, array index assignment, pointer arithmetic)
  • Trace input to write: Follow data flow from source (user input, file data, network packets, string parameters) to the buffer write
  • Compare sizes: Determine the allocated buffer size vs. the amount of data being written (check malloc/array size vs. input length)
  • Look for missing bounds checks: Identify where the code fails to validate that write size fits within buffer capacity

Validate write operations with bounds checking (Primary Defense)

  • Perform bounds checking before all write operations: Ensure index >= 0 && index < buffer_size before writing
  • Validate array indices and buffer sizes: Check offset + length <= buffer_size to prevent overflow
  • Use safe APIs that prevent OOB access:
    • C: Use strncpy, snprintf instead of strcpy, sprintf
    • C++: Use std::string, std::vector instead of C-style arrays
    • Safe string functions: strlcpy (BSD), strcpy_s (Windows), bounds-checked equivalents
  • Validate write size against buffer capacity: Don't trust user-supplied length fields

Use memory-safe languages and libraries

  • Prefer languages with automatic bounds checking: Java, C#, Python, Rust (prevent OOB writes by design)
  • Use safe string functions: Replace strcpy with strncpy, sprintf with snprintf, strcat with strncat
  • Utilize smart pointers and RAII in C++: std::unique_ptr, std::shared_ptr, std::vector manage memory automatically
  • Use safe containers: std::string, std::vector, std::array over raw C arrays

Implement runtime protection mechanisms

  • Enable compiler protections: Stack canaries (detect buffer overflows), ASLR (randomize memory layout), DEP (prevent code execution on stack)
  • Use AddressSanitizer during development: Compile with -fsanitize=address (GCC/Clang) to catch memory errors
  • Enable runtime bounds checking: Use debug builds with bounds checking, sanitizers, valgrind
  • Set compiler security flags: -fstack-protector-strong, -D_FORTIFY_SOURCE=2, -Wl,-z,relro,-z,now

Monitor and test for memory safety issues

  • Use fuzzing and penetration testing tools (AFL, libFuzzer, AddressSanitizer)
  • Enable compiler warnings (-Wall -Wextra -Werror) and fix all warnings
  • Run Static Analysis tools regularly as part of your SDLC
  • Perform code review with security-aware developers
  • Test with malicious inputs (oversized data, negative lengths, integer overflow)

Test the fix thoroughly with edge cases

  • Test with boundary values (maximum buffer size, zero-length writes, null pointers)
  • Test with oversized inputs (attempt to write more than buffer can hold)
  • Test with negative indices or lengths (if using signed types)
  • Verify regression tests ensure fix doesn't break functionality
  • Re-scan with security scanner to confirm the issue is resolved

Additional Resources