{"schema":"threatline.record/2","record":{"id":"CVE-2026-113662","aliases":["GHSA-jqw5-w6h3-44g6"],"summary":"ApostropheCMS import-export: NoSQL injection via update-key value lets a crafted import match and overwrite an unidentified document","details":"## 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.","categories":["Libraries & packages"],"product":"@apostrophecms/import-export","vendor":"apostrophecms","ecosystem":"npm","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-jqw5-w6h3-44g6","source_modified_at":"2026-10-20T18:19:20Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"@apostrophecms/import-export"},"range":"< 3.7.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-113662","source_modified_at":"2026-10-20T19:05:20.680Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"apostrophe","vendor":"apostrophecms","versions":[{"version":"< 4.33.0","status":"affected"}],"defaultStatus":null},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-113662","source_modified_at":"2026-10-20T19:05:20.680Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"import-export","vendor":"@apostrophecms","versions":[{"version":"< 3.7.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-jqw5-w6h3-44g6","source_modified_at":"2026-10-20T18:30:03.585162852Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"@apostrophecms/import-export","ecosystem":"npm","purl":"pkg:npm/%40apostrophecms/import-export"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.7.0"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-jqw5-w6h3-44g6","source_modified_at":"2026-10-20T18:19:20Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"@apostrophecms/import-export"},"version":"3.7.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-jqw5-w6h3-44g6","source_modified_at":"2026-10-20T18:30:03.585162852Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"@apostrophecms/import-export","ecosystem":"npm","purl":"pkg:npm/%40apostrophecms/import-export"},"version":"3.7.0"}],"cvss":5.4,"severity":"Medium","kev":{"listed":false},"epss":{"probability":0.003,"percentile":0.21621,"score_date":"2026-10-23"},"published_at":"2026-10-20T17:13:07.765Z","modified_at":"2026-10-20T19:05:20.680Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-jqw5-w6h3-44g6","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-20T18:19:20Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-113662","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-20T19:05:20.680Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-jqw5-w6h3-44g6","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-20T18:30:03.585162852Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-113662","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-jqw5-w6h3-44g6","tags":["x_refsource_CONFIRM"]},{"source":"CVE List","url":"https://github.com/apostrophecms/apostrophe/commit/9500b8b0e1d630d5e07fbb5fd2c25ed0943845ce","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/apostrophecms/apostrophe/commit/f84fd41cbf6c22eb8d0008fc9c25df1f7130b350","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/apostrophecms/apostrophe/releases/tag/@apostrophecms/import-export@3.7.0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-jqw5-w6h3-44g6","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"none","automatable":"no","technical_impact":"partial","assessed_at":"2026-10-20T19:05:10.314841Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-20T19:05:20.680Z","content_hash":"16577ae72bf78ceb39ad747b8ab82d4865ec9e0b3c58a4bf588a6fcf37bceb0b"}}
