Safeguard
Application Security•

CWE-193 Off-by-one Error: Small Mistake, Large Consequences

A boundary that is one too large or one too small can corrupt memory or crash a service. How CWE-193 happens in C code and how to avoid it.

Safeguard Security Team
3 min read

CWE-193, Off-by-one Error, means a product calculates or uses a maximum or minimum value that is one more, or one less, than the correct value. It is a base level weakness MITRE associates mostly with C, though the logic can occur anywhere.

How it happens

Classic sources are loop bounds with the wrong comparison, array indexes at the length instead of length minus one, and forgetting space for a terminating null byte.

// Vulnerable: needs len + 1 bytes for the terminator
char *copy = malloc(strlen(src));
strcpy(copy, src);                  // writes one byte past the end
// Fixed
size_t n = strlen(src) + 1;
char *copy = malloc(n);
memcpy(copy, src, n);
// Vulnerable loop bound
for (int i = 0; i <= N; i++) { a[i] = 0; }   // a has N elements

MITRE's observed examples show how serious a single byte can be. CVE-2003-0252 allowed remote attackers to cause a denial of service and possibly execute arbitrary code via requests that do not contain newlines. CVE-2001-1391 was an off-by-one vulnerability in a driver that allowed users to modify kernel memory. CVE-2002-0083 let local users or remote malicious servers gain privileges. CVE-2002-0653 was an off-by-one buffer overflow in a server function that allowed local users to execute code as the server user via .htaccess files with long entries.

What an attacker gains

MITRE lists:

  • Availability: crashes and instability, with infinite loops likely when loop indexes are involved.
  • Integrity: modified memory.
  • Confidentiality, availability and access control: execution of unauthorized code, though MITRE says this is usually outside the implicit security policy.

How to find it

MITRE says automated static analysis (SAST) can find some instances by modelling data flow. In review, look at every boundary comparison and every allocation with a string length, and ask whether the terminator is counted. Run tests with a memory sanitizer, since single byte overruns often pass silently otherwise.

How to fix it

The record lists no mitigations, so these are general steps.

  1. Use bounded, length aware APIs, and pass the destination size, not the source length.
  2. Prefer half open ranges, written i less than N, and be consistent.
  3. Write boundary tests at length minus one, length, and length plus one.
  4. Use memory safe languages or containers where you can.

Quick check

What is the most common off-by-one with strings? Forgetting that C strings need one extra byte for the terminating null.

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.