NULL Pointer Dereference

Description

NULL Pointer Dereference occurs when an application dereferences a pointer that it expects to be valid but is actually NULL, typically causing a crash or program exit. A NULL pointer dereference happens when code attempts to read from or write to memory through a pointer that has not been initialized, has been set to NULL, or has had its referenced memory freed. In languages like C and C++, dereferencing a NULL pointer is undefined behavior that usually results in a segmentation fault or access violation. While historically considered primarily a reliability issue, NULL pointer dereferences can sometimes be exploited for code execution under certain conditions.

Risk

NULL pointer dereference is consistently ranked in the CWE Top 25 Most Dangerous Software Weaknesses. CVE-2025-49694 in Microsoft Windows Server 2025 allows privilege escalation through a NULL pointer dereference in the Brokering File System component (CVSS 7.8). CVE-2025-46404 in Entr'ouvert Lasso enables remote denial of service through malformed SAML responses. CVE-2025-42902 in SAP NetWeaver AS ABAP allows unauthenticated attackers to crash SAP work processes. While most NULL dereferences cause denial of service, some can be exploited for code execution, particularly when combined with memory mapping at address 0 or in kernel space.

Solution

Always validate pointers before dereferencing them. Initialize pointers to NULL and check before use. Use static analysis tools to detect potential NULL dereferences. Implement defensive programming practices with explicit NULL checks after allocation or when receiving pointers from external sources. Use smart pointers in C++ to manage memory safely. Enable compiler warnings for NULL pointer issues. In critical systems, consider using languages with built-in NULL safety (Rust, Kotlin, Swift). Map NULL address as non-accessible to prevent exploitation.

Common Consequences

ImpactDetails
AvailabilityScope: Denial of Service

NULL pointer dereference typically crashes the application, causing service disruption.
IntegrityScope: Code Execution

In rare cases, particularly in kernel code, NULL dereferences can be exploited for arbitrary code execution.
Access ControlScope: Privilege Escalation

Kernel NULL pointer dereferences can lead to local privilege escalation.

Example Code + Solution Code

Vulnerable Code

// VULNERABLE: No NULL check after malloc
#include <stdlib.h>
#include <string.h>

void process_data(size_t size) {
    char* buffer = malloc(size);
    // malloc can return NULL if allocation fails!
    strcpy(buffer, "data");  // NULL dereference if malloc failed
}

// VULNERABLE: No NULL check on function return
struct User* find_user(int id);

void update_user(int user_id) {
    struct User* user = find_user(user_id);
    // find_user might return NULL if user not found!
    user->status = ACTIVE;  // NULL dereference crash
}

// VULNERABLE: Dereferencing freed pointer
void cleanup(struct Resource* res) {
    free(res->data);
    // res->data is now invalid (use-after-free possibility)
    printf("Data: %s\n", res->data);  // Undefined behavior
}
// VULNERABLE: Not checking optional/pointer
class UserManager {
public:
    User* findUser(int id) {
        auto it = users_.find(id);
        if (it == users_.end()) return nullptr;
        return &it->second;
    }

    void updateUserEmail(int id, const std::string& email) {
        User* user = findUser(id);
        // No NULL check - crash if user not found!
        user->email = email;
    }
};

// VULNERABLE: Exception might leave pointer NULL
void initializeResource() {
    Resource* resource = nullptr;
    try {
        resource = createResource();  // May throw
    } catch (...) {
        // resource is still NULL
    }
    resource->initialize();  // NULL dereference if exception occurred
}
// VULNERABLE: Unboxing null Integer
public void processAge(Integer age) {
    // age might be null
    int ageValue = age;  // NullPointerException if age is null
    System.out.println("Age: " + ageValue);
}

// VULNERABLE: Method chain without null checks
public String getUserCity(Order order) {
    // Any of these can be null!
    return order.getUser().getAddress().getCity();
}

Fixed Code

// SAFE: Check for NULL after allocation
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int process_data_safe(size_t size) {
    if (size == 0 || size > MAX_BUFFER_SIZE) {
        return -EINVAL;
    }

    char* buffer = malloc(size);
    if (buffer == NULL) {
        // Handle allocation failure gracefully
        return -ENOMEM;
    }

    // Safe to use buffer now
    strncpy(buffer, "data", size - 1);
    buffer[size - 1] = '\0';

    // ... use buffer ...

    free(buffer);
    return 0;
}

// SAFE: Check function return value
struct User* find_user(int id);

int update_user_safe(int user_id) {
    struct User* user = find_user(user_id);

    if (user == NULL) {
        // Handle user not found case
        log_error("User %d not found", user_id);
        return -ENOENT;
    }

    user->status = ACTIVE;
    return 0;
}

// SAFE: Set pointer to NULL after free
void cleanup_safe(struct Resource* res) {
    if (res == NULL) return;

    if (res->data != NULL) {
        free(res->data);
        res->data = NULL;  // Prevent use-after-free
    }
}
// SAFE: Using optional and checking before use
#include <optional>
#include <memory>

class UserManager {
public:
    std::optional<std::reference_wrapper<User>> findUser(int id) {
        auto it = users_.find(id);
        if (it == users_.end()) return std::nullopt;
        return std::ref(it->second);
    }

    bool updateUserEmail(int id, const std::string& email) {
        auto userOpt = findUser(id);
        if (!userOpt.has_value()) {
            return false;  // User not found
        }
        userOpt->get().email = email;
        return true;
    }
};

// SAFE: Using smart pointers
void processResource() {
    auto resource = std::make_unique<Resource>();
    // No need for NULL check - make_unique throws on failure
    resource->initialize();
}  // Automatic cleanup

// SAFE: RAII pattern with exception safety
class ResourceGuard {
public:
    ResourceGuard() : resource_(createResource()) {
        if (!resource_) {
            throw std::runtime_error("Failed to create resource");
        }
    }

    Resource& get() { return *resource_; }

private:
    std::unique_ptr<Resource> resource_;
};
// SAFE: Explicit null checking
public void processAge(Integer age) {
    if (age == null) {
        throw new IllegalArgumentException("Age cannot be null");
    }
    int ageValue = age;
    System.out.println("Age: " + ageValue);
}

// SAFE: Using Optional
public Optional<String> getUserCity(Order order) {
    return Optional.ofNullable(order)
        .map(Order::getUser)
        .map(User::getAddress)
        .map(Address::getCity);
}

// SAFE: Null-safe method chain
public String getUserCitySafe(Order order) {
    if (order == null) return "Unknown";
    User user = order.getUser();
    if (user == null) return "Unknown";
    Address address = user.getAddress();
    if (address == null) return "Unknown";
    return address.getCity() != null ? address.getCity() : "Unknown";
}

// SAFE: Using Objects.requireNonNull for parameters
public void createUser(String name, String email) {
    this.name = Objects.requireNonNull(name, "Name cannot be null");
    this.email = Objects.requireNonNull(email, "Email cannot be null");
}

Exploited in the Wild

Microsoft Windows Server 2025 (Microsoft, 2025)

CVE-2025-49694 in Microsoft Windows Server 2025 Brokering File System allows local attackers to escalate privileges through NULL pointer dereference, rated CVSS 7.8 high severity with impacts on confidentiality, integrity, and availability.

Entr'ouvert Lasso SAML Library (Entr'ouvert, 2025)

CVE-2025-46404 in Entr'ouvert Lasso 2.5.1 allows remote unauthenticated attackers to cause denial of service by sending malformed SAML responses that trigger NULL pointer dereference during signature verification.

SAP NetWeaver AS ABAP (SAP, 2025)

CVE-2025-42902 in SAP NetWeaver allows unauthenticated attackers to crash SAP work processes by sending corrupted SAP Logon or Assertion Tickets that trigger NULL pointer dereference.


Tools to test/exploit

  • Valgrind — detect memory errors including NULL dereferences.

  • AddressSanitizer — detect memory bugs at runtime.

  • Coverity — static analysis for NULL dereference detection.


CVE Examples


References

  1. MITRE. "CWE-476: NULL Pointer Dereference." https://cwe.mitre.org/data/definitions/476.html

  2. CERT. "EXP34-C. Do not dereference null pointers." https://wiki.sei.cmu.edu/confluence/display/c/EXP34-C.+Do+not+dereference+null+pointers