Safeguard
Application Security•

CWE-476 NULL Pointer Dereference: Causes, Detection and Fixes

A NULL pointer dereference usually crashes the process, and in rare cases does more. See how it appears in C and Java, how to find it and how to prevent it.

Safeguard Security Team
4 min read

CWE-476, NULL Pointer Dereference, happens when code uses a pointer or reference that it expects to be valid but is NULL. MITRE rates the entry Stable, and lists C, C++, Java, C# and Go.

For a network service, a bug that lets one request kill the process is a real availability problem, even when it never leads to code execution. It is also one of the most common crash causes in real code.

How it happens

Something returns NULL to signal failure, and the caller does not check.

// Vulnerable: malloc and fopen can both return NULL
char *buf = malloc(len);
memcpy(buf, input, len);        /* crashes if buf is NULL */

FILE *f = fopen(path, "r");
fgets(line, sizeof line, f);    /* crashes if f is NULL */

The same thing happens in Java and C# as a NullPointerException or NullReferenceException, usually when a lookup returns nothing.

User u = users.get(id);      // returns null when id is unknown
return u.getName();          // throws NullPointerException

The record gives a range of observed cases. CVE-2024-41130 is a C++ library for LLM inference with a NULL dereference when a read operation fails. CVE-2005-3274 is a race condition that corrupts a table if a timer fires while it is being changed, ending in a NULL dereference, with locking also involved. CVE-2002-1912 is a large number of packets leading to a NULL dereference. CVE-2005-0772 is a packet with an invalid error status value that triggers one.

What an attacker gains

MITRE lists two outcomes.

  • Availability. A NULL dereference usually fails the process unless exception handling is available and in use. Even with exception handling, it can be very hard to return the software to a safe state.
  • Integrity and confidentiality, in rare cases. When NULL equals the 0x0 address and privileged code can access it, reading or writing memory is possible, which may lead to code execution.

How to find it

MITRE lists several methods.

  • Fuzzing, stress testing with odd inputs, and fault injection, which feed many diverse inputs and watch for crashes.
  • Manual dynamic testing of unlikely error conditions: low memory, insufficient permissions, a transaction interrupted midway, connectivity disabled.
  • Static analysis, which can model data flow to a dereference with no prior check.
  • Compiler assisted runtime checks such as AddressSanitizer for C and C++, which MITRE rates as moderately effective and which needs crafted inputs to reach the faulty code.

How to fix it

MITRE's mitigations, in plain steps.

  1. Check any pointer that could be modified or come from a function that can return NULL before you use it.
  2. In multithreaded code, use proper locking around the check and the use. Checking a return value is usually enough alone, but a race (CWE-362) can still change the pointer between check and use.
  3. Check the result of every function that returns a value and confirm it is not NULL before acting on it.
  4. Where you can choose, select a language that is not susceptible to these issues.
  5. Validate every variable that receives data from external sources so it only holds expected values.
  6. Explicitly initialize variables and data stores at declaration or just before first use.
char *buf = malloc(len);
if (buf == NULL) {
    return -1;               /* fail cleanly */
}
memcpy(buf, input, len);
User u = users.get(id);
if (u == null) {
    throw new NotFoundException(id);
}
return u.getName();

Try it yourself

See how a code scan flags a dereference that follows an unchecked call.

Click through it at your own pace, or open it full screen.

Quick check

If I check the pointer, am I safe in threaded code?

Not always. Another thread can change the pointer after your check. Hold a lock across the check and the use.

Why does fuzzing find these well?

Crashes are easy to detect. A fuzzer keeps changing inputs until one reaches an unchecked NULL, and the crash tells you exactly where.

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.