{"id":"GHSA-jqw5-w6h3-44g6","revision":"911efe7003844dbe9ae7aa78b9a0856a","records":[{"revision":"911efe7003844dbe9ae7aa78b9a0856a","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-jqw5-w6h3-44g6","aliases":["CVE-2026-113662"],"title":"ApostropheCMS import-export: NoSQL injection via update-key value lets a crafted import match and overwrite an unidentified document","description":"## Summary\n\n`@apostrophecms/import-export`'s update-by-key feature lets an imported\ndocument carry a `<field>:key` property (for example `slug:key`) whose\nvalue is used to find an existing document to update instead of inserting\na new one. `getUpdateKey()`/`insertOrUpdateDocWithKey()`\n(`lib/methods/import.js`) use that value directly as a MongoDB query value\nwith no laundering:\n\n```js\nconst matchingDraftPromise = manager.findForEditing(\n  req.clone({ mode: 'draft' }),\n  {\n    aposMode: 'draft',\n    [updateField]: doc[updateKey]\n  }).toObject();\n```\n\nArchive documents are parsed with EJSON (see `lib/formats/gzip.js`), which\nrevives objects such as `{ $ne: null }` as live values, the same untrusted\ndata source and revival mechanism already fixed once in this module for\n`findSingletonAposDocId`/`findParkedAposDocId` in GHSA-79qf-vqgc-7xx3. That\nfix did not touch `insertOrUpdateDocWithKey`, so the identical class of bug\nsurvives here: a crafted `\"slug:key\": { \"$ne\": null }` entry in an\narchive's `aposDocs.json` makes the import match (and then update) an\nexisting document the archive's author never actually identified, instead\nof failing to find a match.\n\n## Impact\n\nReaching this requires only an authenticated session with import access to\nthe target type (the built-in contributor role holds this, matching the\nprecondition of GHSA-79qf-vqgc-7xx3), and no admin interaction. Because the\nmatch uses a MongoDB operator instead of an exact value, it is not limited\nto a document the importer already knows the identifying field of: any\nexisting document the importer has generic edit rights on and that\nsatisfies the operator (which `{ $ne: null }` trivially does for any doc\nwith a non-null value in that field) is a candidate, and Apostrophe's\n`findForEditing` permission filter, not the update-key logic, is the only\nthing narrowing which document actually gets matched and overwritten.\n\nLive-verified: a contributor-role request importing a document containing\n`\"slug:key\": { \"$ne\": null }` had its content applied to an existing,\nunrelated draft article, overwriting its title, while the importer never\nspecified that article's real slug.\n\n## Affected versions\n\nConfirmed on `main` branch HEAD as of 2026-09-04,\n`packages/import-export/lib/methods/import.js`.\n\n## Suggested fix\n\nLaunder `doc[updateKey]` to a plain string (mirroring the fix already\napplied to `type`/`aposLocale`/`parkedId` in GHSA-79qf-vqgc-7xx3) before\nusing it as a query value, and fall back to the insert path when it is not\na usable string.","state":0,"publishedAt":"2026-10-20T18:19:19+00:00","modifiedAt":"2026-10-20T18:30:03.5851629+00:00","affected":[{"ecosystem":"npm","name":"@apostrophecms/import-export","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"3.7.0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-jqw5-w6h3-44g6","https://github.com/apostrophecms/apostrophe/commit/9500b8b0e1d630d5e07fbb5fd2c25ed0943845ce","https://github.com/apostrophecms/apostrophe/commit/f84fd41cbf6c22eb8d0008fc9c25df1f7130b350","https://github.com/apostrophecms/apostrophe","https://github.com/apostrophecms/apostrophe/releases/tag/@apostrophecms/import-export@3.7.0"],"sourceUrl":"https://github.com/advisories/GHSA-jqw5-w6h3-44g6","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-jqw5-w6h3-44g6","identifiers":["GHSA-jqw5-w6h3-44g6","CVE-2026-113662"]},"retained":false,"historicalAffected":[]}],"coverage":[]}