GitHub Advisoryadvisory · npm
GHSA-jqw5-w6h3-44g6 ApostropheCMS import-export: NoSQL injection via update-key value lets a crafted import match and overwrite an unidentified document
MEDIUM
Official page ↗
- Aliases
- CVE-2026-113662
- Ecosystem
- npm
- Packages
- @apostrophecms/import-export
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
- Weaknesses
- CWE-284, CWE-943
- Reviewed
- 2026-10-20
Affected packages
• npm @apostrophecms/import-export: < 3.7.0 → fixed in 3.7.0
Description
Summary
`@apostrophecms/import-export`'s update-by-key feature lets an imported
document carry a `:key` property (for example `slug:key`) whose
value is used to find an existing document to update instead of inserting
a new one. `getUpdateKey()`/`insertOrUpdateDocWithKey()`
(`lib/methods/import.js`) use that value directly as a MongoDB query value
with no laundering:
```js
const matchingDraftPromise = manager.findForEditing(
req.clone({ mode: 'draft' }),
{
aposMode: 'draft',
[updateField]: doc[updateKey]
}).toObject();
```
Archive documents are parsed with EJSON (see `lib/formats/gzip.js`), which
revives objects such as `{ $ne: null }` as live values, the same untrusted
data source and revival mechanism already fixed once in this module for
`findSingletonAposDocId`/`findParkedAposDocId` in GHSA-79qf-vqgc-7xx3. That
fix did not touch `insertOrUpdateDocWithKey`, so the identical class of bug
survives here: a crafted `"slug:key": { "$ne": null }` entry in an
archive's `aposDocs.json` makes the import match (and then update) an
existing document the archive's author never actually identified, instead
of failing to find a match.
Impact
Reaching this requires only an authenticated session with import access to
the target type (the built-in contributor role holds this, matching the
precondition of GHSA-79qf-vqgc-7xx3), and no admin interaction. Because the
match uses a MongoDB operator instead of an exact value, it is not limited
to a document the importer already knows the identifying field of: any
existing document the importer has generic edit rights on and that
satisfies the operator (which `{ $ne: null }` trivially does for any doc
with a non-null value in that field) is a candidate, and Apostrophe's
`findForEditing` permission filter, not the update-key logic, is the only
thing narrowing which document actually gets matched and overwritten.
Live-verified: a contributor-role request importing a document containing
`"slug:key": { "$ne": null }` had its content applied to an existing,
unrelated draft article, overwriting its title, while the importer never
specified that article's real slug.
Affected versions
Confirmed on `main` branch HEAD as of 2026-09-04,
`packages/import-export/lib/methods/import.js`.
Suggested fix
Launder `doc[updateKey]` to a plain string (mirroring the fix already
applied to `type`/`aposLocale`/`parkedId` in GHSA-79qf-vqgc-7xx3) before
using it as a query value, and fall back to the insert path when it is not
a usable string.
Related
Alias · CVE (1)
- CVE-2026-113662 ApostropheCMS is an open-source Node.js content management system. vulnerability
References
- https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-jqw5-w6h3-44g6 web
- https://github.com/apostrophecms/apostrophe/commit/9500b8b0e1d630d5e07fbb5fd2c25ed0943845ce web
- https://github.com/apostrophecms/apostrophe/commit/f84fd41cbf6c22eb8d0008fc9c25df1f7130b350 web
- https://github.com/apostrophecms/apostrophe package
- https://github.com/apostrophecms/apostrophe/releases/tag/@apostrophecms/[email protected] web