The vulnerability, CVE-2026-71553, is a second-order prototype pollution issue in ApostropheCMS affecting versions up to 4.32.0. The core of the problem lies within the apos.util.set() and apos.util.get() utility functions, which are used to manipulate object properties via dot-notation paths. These functions failed to distinguish between 'own' properties of an object and 'inherited' properties from its prototype chain.
Specifically, the PATCH /api/v1/article/:id endpoint accepted input that could include paths like toString.call. When processed by apos.util.set() and apos.util.get(), these paths would traverse the prototype chain, allowing an authenticated editor to reach and modify Object.prototype.toString.call. Overwriting this shared function's call property would cause a persistent denial of service across the entire application process, as many internal operations (including those in the MongoDB driver) rely on Object.prototype.toString.call().
The provided patch (commit 5a3746aaed49761e171c2cbfe793267c959829fd) introduces a new helper function ownProperty(o, p) which uses Object.hasOwn(o, p) to explicitly check if a property p belongs directly to object o and not its prototype. This check is then integrated into both apos.util.get() and apos.util.set().
- In
apos.util.get(), the condition for returning undefined (i.e., refusing to read a property) was expanded to include !ownProperty(o, p). This prevents the function from reading inherited properties that could lead to prototype pollution.
- In
apos.util.set(), a new check if (!ownProperty(o, p)) was added before traversing to the next object in the path. If an inherited property is encountered, an 'invalid' error is thrown, preventing the modification of shared prototype properties.
Therefore, the functions apos.util.get and apos.util.set are identified as vulnerable because their previous implementations lacked the necessary checks to prevent prototype chain traversal and modification, directly leading to the described denial-of-service vulnerability.