Skip to content

utils: fix decode_pointer_inplace dropping bytes after escapes (CVE-2026-29036) - #1120

Open
w4ffl35 wants to merge 1 commit into
DaveGamble:masterfrom
Capsize-Games:fix-cve-2026-29036
Open

w4ffl35 wants to merge 1 commit into
DaveGamble:masterfrom
Capsize-Games:fix-cve-2026-29036

Conversation

@w4ffl35

@w4ffl35 w4ffl35 commented Oct 27, 2026

Copy link
Copy Markdown

Fixes a wrong-key vulnerability in JSON Patch pointer decoding (CVE-2026-29036: crafted ~0/~1 sequences make add/remove/replace target wrong object keys, silently corrupting data or deleting unintended keys).

Root cause (two defects in decode_pointer_inplace, cJSON_Utils.c):

  1. The write pointer advanced on every loop iteration but passthrough bytes were never copied down, so any escape not at the end of a token truncated the decoded name — /a~1b decoded to a~ instead of a/b.
  2. For ~1, / was written to decoded[1] instead of decoded[0], scrambling the byte after the escape.

No out-of-bounds write (writes stay within already-read positions), but the corrupted child name is passed to detach/add, hence wrong-key effects. The read path (compare_pointers) was already correct, which is why test/get behaved while add/remove/replace did not.

Fix: compact properly — escapes collapse two bytes into one, every other byte copied down; invalid escapes abort exactly as before. Regression cases 16/17 added to tests/json-patch-tests/cjson-utils-tests.json (replace and remove via /a~1b on a doc containing both a/b and a~b).

Evidence (fresh clone at 6d9f244 + #1119 test commit, ASan+UBSan build):

AI disclosure: drafted with AI assistance (Muse), red/green verified by the author; independent review welcome.

…026-29036)

decode_pointer_inplace advanced the write pointer on every loop iteration
but never copied passthrough bytes down, so any escape not at end of token
truncated the decoded name ('/a~1b' became 'a~'). Worse, the old code wrote
'/' to decoded[1] instead of decoded[0] for ~1. JSON Patch add/remove/replace
then targeted wrong keys or failed, enabling silent data corruption and
wrong-key deletion via crafted ~0/~1 sequences.

Rewrite compacts properly: escapes collapse two bytes into one, all other
bytes copied down; decoded never overtakes the read cursor. Invalid escapes
still abort as before. Regression cases 16/17 in cjson-utils-tests.json.

Red/green: new cases fail before (apply error 13), all 3 patch suites pass
after; full ctest 21/22 (old_utils_tests fails only on the unrelated
not-yet-merged DaveGamble#1109 variant, identical before/after this change).
@w4ffl35
w4ffl35 force-pushed the fix-cve-2026-29036 branch from b079c1b to d77a516 Compare October 27, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant