Summary
In cJSON_Utils.c, several code paths check whether a field is a string using cJSON_IsString(), and then directly use item->valuestring (e.g., via strcmp, strlen, or indexing).
However, cJSON_IsString() only checks the type tag and does not guarantee that valuestring is non-NULL.
It is possible to construct a cJSON_String item whose valuestring is NULL using public APIs such as cJSON_CreateStringReference(NULL).
Even if such input is considered invalid, the JSON Patch code path currently assumes that cJSON_IsString() is sufficient before dereferencing valuestring. This can lead to a crash instead of graceful rejection.
Affected version
- cJSON 1.7.19
- Code path: JSON Patch handling in
cJSON_Utils.c
Relevant code
cJSON_IsString() only checks the type:
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
{
if (item == NULL)
{
return false;
}
return (item->type & 0xFF) == cJSON_String;
}
Example usage in decode_patch_operation():
cJSON *operation = get_object_item(patch, "op", case_sensitive);
if (!cJSON_IsString(operation))
{
return INVALID;
}
if (strcmp(operation->valuestring, "add") == 0)
{
return ADD;
}
Similar patterns exist in apply_patch() for fields like path and from, where valuestring is used without NULL checks.
Proof of concept
Case 1: NULL op->valuestring
#include "cJSON.h"
#include "cJSON_Utils.h"
int main(void)
{
cJSON *target = cJSON_CreateObject();
cJSON *patches = cJSON_CreateArray();
cJSON *patch = cJSON_CreateObject();
cJSON_AddItemToObject(patch, "op", cJSON_CreateStringReference(NULL));
cJSON_AddItemToObject(patch, "path", cJSON_CreateString(""));
cJSON_AddItemToObject(patch, "value", cJSON_CreateNumber(1));
cJSON_AddItemToArray(patches, patch);
return cJSONUtils_ApplyPatches(target, patches);
}
Case 2: NULL path->valuestring
#include "cJSON.h"
#include "cJSON_Utils.h"
int main(void)
{
cJSON *target = cJSON_CreateObject();
cJSON *patches = cJSON_CreateArray();
cJSON *patch = cJSON_CreateObject();
cJSON_AddItemToObject(patch, "op", cJSON_CreateString("remove"));
cJSON_AddItemToObject(patch, "path", cJSON_CreateStringReference(NULL));
cJSON_AddItemToArray(patches, patch);
return cJSONUtils_ApplyPatches(target, patches);
}
Case 3: NULL from->valuestring
#include "cJSON.h"
#include "cJSON_Utils.h"
int main(void)
{
cJSON *target = cJSON_Parse("{\"a\":1}");
cJSON *patches = cJSON_CreateArray();
cJSON *patch = cJSON_CreateObject();
cJSON_AddItemToObject(patch, "op", cJSON_CreateString("move"));
cJSON_AddItemToObject(patch, "path", cJSON_CreateString("/b"));
cJSON_AddItemToObject(patch, "from", cJSON_CreateStringReference(NULL));
cJSON_AddItemToArray(patches, patch);
return cJSONUtils_ApplyPatches(target, patches);
}
Build and run
gcc poc.c cJSON.c cJSON_Utils.c -o poc
./poc
On Windows (MinGW), this results in access violation (0xC0000005).
Expected behavior
Invalid patch fields with NULL string values should be rejected with an error code instead of causing a crash.
Suggested fix
Add an additional NULL check before using valuestring. For example:
static cJSON_bool is_valid_patch_string(const cJSON * const item)
{
return cJSON_IsString(item) && (item->valuestring != NULL);
}
Then use it for patch fields such as op, path, instead of relying on cJSON_IsString() alone
Summary
In
cJSON_Utils.c, several code paths check whether a field is a string usingcJSON_IsString(), and then directly useitem->valuestring(e.g., viastrcmp,strlen, or indexing).However,
cJSON_IsString()only checks the type tag and does not guarantee thatvaluestringis non-NULL.It is possible to construct a
cJSON_Stringitem whosevaluestringis NULL using public APIs such ascJSON_CreateStringReference(NULL).Even if such input is considered invalid, the JSON Patch code path currently assumes that
cJSON_IsString()is sufficient before dereferencingvaluestring. This can lead to a crash instead of graceful rejection.Affected version
cJSON_Utils.cRelevant code
cJSON_IsString()only checks the type:Example usage in
decode_patch_operation():Similar patterns exist in
apply_patch()for fields likepathandfrom, wherevaluestringis used without NULL checks.Proof of concept
Case 1: NULL
op->valuestringCase 2: NULL
path->valuestringCase 3: NULL
from->valuestringBuild and run
On Windows (MinGW), this results in access violation (
0xC0000005).Expected behavior
Invalid patch fields with NULL string values should be rejected with an error code instead of causing a crash.
Suggested fix
Add an additional NULL check before using
valuestring. For example:Then use it for patch fields such as op, path, instead of relying on cJSON_IsString() alone