CVE-2026-113659
ApostropheCMS: Client-side Prototype Pollution in apos.http.parseQuery leading to DOM-based XSS against authenticated users
ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an unauthenticated attacker can send a crafted link whose query string is automatically parsed by apos.http.parseQuery when an authenticated victim loads a page with the admin bundle. The parser accepts the special proto, constructor, and prototype path keys, allowing browser prototype mutation that can reach an unsafe DOM sink and execute script in the victim's session; anonymous visitors do not load the affected admin context. This issue is fixed in version 4.33.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.1
ApostropheCMS: Client-side Prototype Pollution in apos.http.parseQuery leading to DOM-based XSS against authenticated users
ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an unauthenticated attacker can send a crafted link whose query string is automatically parsed by apos.http.parseQuery when an authenticated victim loads a page with the admin bundle. The parser accepts the special proto, constructor, and prototype path keys, allowing browser prototype mutation that can reach an unsafe DOM sink and execute script in the victim's session; anonymous visitors do not load the affected admin context. This issue is fixed in version 4.33.0.
- Record
CVE-2026-113659- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79, CWE-1321
- Updated
- 2026-11-02
EUVDEUVD-2026-105207
6.1
ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an unauthenticated attacker can send a crafted link whose query string is automatically parsed by apos.http.parseQuery when an authenticated victim loads a page with the admin bundle. The parser accepts the special proto, constructor, and prototype path keys, allowing browser prototype mutation that can reach an unsafe DOM sink and execute script in the victim's session; anonymous visitors do not load the affected admin context. This issue is fixed in version 4.33.0.
- Record
EUVD-2026-105207- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-m2m5-rw3w-cwmj
6.1
ApostropheCMS: Client-side Prototype Pollution in apos.http.parseQuery leading to DOM-based XSS against authenticated users
Summary
The client-side helper apos.http.parseQuery() in ApostropheCMS builds a nested object
from a URL query string without sanitizing the keys __proto__, constructor, or
prototype. Parsing an attacker-controlled query string therefore writes arbitrary
properties onto Object.prototype (client-side prototype pollution).
ApostropheCMS's admin UI calls this parser with window.location.search on every
authenticated page load (the admin context bar's data() initializer). Because the admin
UI is built on Vue, a polluted, enumerable property on Object.prototype is then picked up
by Vue's standard element-mount routine and written to the DOM as an element property,
turning the prototype pollution into DOM-based XSS in the victim's authenticated session.
The escalation gadget is a well-known, general Vue behavior; the novel,
reportable defect is the unsanitized parseQuery source together with the authenticated
trigger, both of which are ApostropheCMS code.
Any user who can get any logged-in user (from the lowest-privileged guest role up to the highest-privileged admin role) to
open a crafted URL can execute arbitrary JavaScript in that user's session.
This is distinct from CVE-2026-53609 (server-side prototype pollution via
apos.util.set() / $pullAll, fixed in 4.31.0): different side (client vs server),
different code path, and the vulnerable code here is present in the current release.
Package
- Ecosystem: npm
- Package:
apostrophe - Affected versions: all 4.x releases, 4.0.0 through 4.32.2 (current
latest). Verified by inspecting the published npm tarballs:[email protected]already contains the vulnerable descent (parentKey = 'root') with no__proto__/constructor/prototypefiltering, and[email protected]is unchanged in this respect. The vulnerableparseQuery()logic was introduced in commit0255086bf(2020-11-12), well before the 4.0 version, so ApostropheCMS 3.x is also affected (the same code ships in 3.x at the older build pathmodules/@apostrophecms/util/ui/public/2-http.js). - Patched versions: none at time of writing.
Details
The issue has three parts. Parts 1 and 2 are ApostropheCMS code and constitute the reportable vulnerability. Part 3 is the escalation gadget, which is standard Vue behavior and is included for completeness.
1. The pollution primitive: source (ApostropheCMS)
modules/@apostrophecms/util/ui/src/http.js, function apos.http.parseQuery()
(line ~301) and its inner patch() (lines ~317–354):
function patch(key, value) {
let match;
let parentKey = 'root';
let context = data; // data = {} (ordinary object)
key = decodeURIComponent(key);
const path = key.split('[');
path.forEach(function(subKey) {
if (subKey === ']') {
/* array handling */
} else if (subKey.match(/^\d+]/)) {
/* numeric index handling */
} else {
match = subKey.replace(']', '');
if (!context[parentKey]) { // (A) truthy check, not an own-property check
context[parentKey] = {};
}
context = context[parentKey]; // (B) descends into whatever this resolves to
parentKey = match;
}
});
value = (value === null) ? value : decodeURIComponent(value);
if (Array.isArray(context[parentKey])) {
context[parentKey].push(value);
} else if (context[parentKey] !== undefined) {
context[parentKey] = [ context[parentKey], value ];
} else {
context[parentKey] = value; // (C) assignment onto the resolved object
}
}
No __proto__, constructor, or prototype key is rejected. Walking the input
__proto__[x]=v:
- Segment
__proto__: at (A),context['__proto__']resolves to the object's inherited prototype (truthy), so the{}initializer is skipped; at (B),contextbecomesObject.prototype. - Segment
x: at (C),Object.prototype['x'] = v.
The truthy guard at…
- Record
GHSA-m2m5-rw3w-cwmj- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79, CWE-1321
- Updated
- 2026-11-02
NVD
6.1
ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an unauthenticated attacker can send a crafted link whose query string is automatically parsed by apos.http.parseQuery when an authenticated victim loads a page with the admin bundle. The parser accepts the special proto, constructor, and prototype path keys, allowing browser prototype mutation that can reach an unsafe DOM sink and execute script in the victim's session; anonymous visitors do not load the affected admin context. This issue is fixed in version 4.33.0.
- Record
CVE-2026-113659- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79, CWE-1321
- Updated
- 2026-11-02
OSV
6.1
ApostropheCMS: Client-side Prototype Pollution in apos.http.parseQuery leading to DOM-based XSS against authenticated users
ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an unauthenticated attacker can send a crafted link whose query string is automatically parsed by apos.http.parseQuery when an authenticated victim loads a page with the admin bundle. The parser accepts the special proto, constructor, and prototype path keys, allowing browser prototype mutation that can reach an unsafe DOM sink and execute script in the victim's session; anonymous visitors do not load the affected admin context. This issue is fixed in version 4.33.0.
- Record
CVE-2026-113659- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-1321, CWE-79
- Updated
- 2026-11-02
OSVGHSA-m2m5-rw3w-cwmj
6.1
ApostropheCMS: Client-side Prototype Pollution in apos.http.parseQuery leading to DOM-based XSS against authenticated users
Summary
The client-side helper apos.http.parseQuery() in ApostropheCMS builds a nested object
from a URL query string without sanitizing the keys __proto__, constructor, or
prototype. Parsing an attacker-controlled query string therefore writes arbitrary
properties onto Object.prototype (client-side prototype pollution).
ApostropheCMS's admin UI calls this parser with window.location.search on every
authenticated page load (the admin context bar's data() initializer). Because the admin
UI is built on Vue, a polluted, enumerable property on Object.prototype is then picked up
by Vue's standard element-mount routine and written to the DOM as an element property,
turning the prototype pollution into DOM-based XSS in the victim's authenticated session.
The escalation gadget is a well-known, general Vue behavior; the novel,
reportable defect is the unsanitized parseQuery source together with the authenticated
trigger, both of which are ApostropheCMS code.
Any user who can get any logged-in user (from the lowest-privileged guest role up to the highest-privileged admin role) to
open a crafted URL can execute arbitrary JavaScript in that user's session.
This is distinct from CVE-2026-53609 (server-side prototype pollution via
apos.util.set() / $pullAll, fixed in 4.31.0): different side (client vs server),
different code path, and the vulnerable code here is present in the current release.
Package
- Ecosystem: npm
- Package:
apostrophe - Affected versions: all 4.x releases, 4.0.0 through 4.32.2 (current
latest). Verified by inspecting the published npm tarballs:[email protected]already contains the vulnerable descent (parentKey = 'root') with no__proto__/constructor/prototypefiltering, and[email protected]is unchanged in this respect. The vulnerableparseQuery()logic was introduced in commit0255086bf(2020-11-12), well before the 4.0 version, so ApostropheCMS 3.x is also affected (the same code ships in 3.x at the older build pathmodules/@apostrophecms/util/ui/public/2-http.js). - Patched versions: none at time of writing.
Details
The issue has three parts. Parts 1 and 2 are ApostropheCMS code and constitute the reportable vulnerability. Part 3 is the escalation gadget, which is standard Vue behavior and is included for completeness.
1. The pollution primitive: source (ApostropheCMS)
modules/@apostrophecms/util/ui/src/http.js, function apos.http.parseQuery()
(line ~301) and its inner patch() (lines ~317–354):
function patch(key, value) {
let match;
let parentKey = 'root';
let context = data; // data = {} (ordinary object)
key = decodeURIComponent(key);
const path = key.split('[');
path.forEach(function(subKey) {
if (subKey === ']') {
/* array handling */
} else if (subKey.match(/^\d+]/)) {
/* numeric index handling */
} else {
match = subKey.replace(']', '');
if (!context[parentKey]) { // (A) truthy check, not an own-property check
context[parentKey] = {};
}
context = context[parentKey]; // (B) descends into whatever this resolves to
parentKey = match;
}
});
value = (value === null) ? value : decodeURIComponent(value);
if (Array.isArray(context[parentKey])) {
context[parentKey].push(value);
} else if (context[parentKey] !== undefined) {
context[parentKey] = [ context[parentKey], value ];
} else {
context[parentKey] = value; // (C) assignment onto the resolved object
}
}
No __proto__, constructor, or prototype key is rejected. Walking the input
__proto__[x]=v:
- Segment
__proto__: at (A),context['__proto__']resolves to the object's inherited prototype (truthy), so the{}initializer is skipped; at (B),contextbecomesObject.prototype. - Segment
x: at (C),Object.prototype['x'] = v.
The truthy guard at…
- Record
GHSA-m2m5-rw3w-cwmj- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-1321, CWE-79
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
apostrophenpm |
before 4.33.0 | 4.33.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-113659 is a medium vulnerability (CVSS 6.1) in Apostrophecms Apostrophe, published October 20, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 28th percentile. Fixed in apostrophe 4.33.0.
References
github.com/apostrophecms/apostrophe/security/advisories/GHSA-m2m5-rw3w-cwmj
github.com/apostrophecms/apostrophe/commit/9500b8b0e1d630d5e07fbb5fd2c25ed0943845ce
github.com/apostrophecms/apostrophe/commit/f84fd41cbf6c22eb8d0008fc9c25df1f7130b350
github.com/apostrophecms/apostrophe/releases/tag/[email protected]
github.com/advisories/GHSA-m2m5-rw3w-cwmj
github.com/CVEProject/cvelistV5/tree/main/cves/2026/113xxx/CVE-2026-113659.json
nvd.nist.gov/vuln/detail/CVE-2026-113659
github.com/apostrophecms/apostrophe
Left out here: the rest of 2 source descriptions. The JSON record has them.