Safeguard
Application Security•

CWE-823 Use of Out-of-range Pointer Offset: Causes and Fixes

Pointer arithmetic with an attacker influenced offset reads or writes the wrong memory. Here is how CWE-823 shows up in file and packet parsers.

Safeguard Security Team
3 min read

CWE-823 applies when code does pointer arithmetic on a valid pointer but uses an offset that can land outside the intended range. The base pointer is fine. The offset is not.

It affects C and C++, and shows up most in code that parses structured data: documents, media files, network packets.

How it happens

Programs use offsets to reach fields inside structured data. MITRE says the offset can be out of range because it comes from an untrusted source, results from a faulty calculation, or comes from another error. If an attacker controls it, they can read or write memory used elsewhere in the program.

Examples from the record:

  • CVE-2009-3129: a spreadsheet program processes a record with an invalid size field that is later used as an offset.
  • CVE-2010-1281: a multimedia player uses an untrusted value from a file in file-pointer calculations.
  • CVE-2009-2694: an instant messaging library does not validate an offset in a packet.
// Vulnerable: offset comes from the file
uint32_t off = read_u32(hdr);
uint8_t *field = base + off;     // no range check
value = *field;

What an attacker gains

MITRE lists reading sensitive memory, crashing the application, and, when the pointer feeds a function call or a write, modifying memory and possibly executing code.

How to find it

Use static analysis, which can track data flow from input to arithmetic, and dynamic analysis with AddressSanitizer or similar. MITRE notes crafted inputs are needed to reach the faulty code, so build a corpus of malformed files and fuzz it.

How to fix it

The record lists no formal mitigations. Practical steps:

  1. Check that every offset is smaller than the size of the containing structure before you add it to a base.
  2. Check that offset plus the size you will read fits in the buffer, written so the addition cannot overflow.
  3. Carry buffer lengths with their pointers, so the check is always possible.
  4. Prefer array indexing with bounds checks, or bounds checked containers.
// Fixed
uint32_t off = read_u32(hdr);
if (off > buf_len || buf_len - off < sizeof(uint8_t)) return -1;
value = base[off];

Quick check

Why write the check as buf_len minus off instead of off plus size?

Adding can wrap around for large values and pass the check. Subtracting after confirming off is not past the end cannot wrap.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.