GHSA-rw26-wwfc-9wvm: CSRF

Published Oct 21, 2026
·
Updated

1. Summary The API endpoint POST /api/v1/@apostrophecms/import-export/clean-export in @apostrophecms/import-export lacks authentication and authorization checks. Any client—including unauthenticated anonymous users who have obtained the standard CSRF cookie from visiting the site—can directly invoke this route and trigger the underlying self.cleanExport(req) method.

---

2. Affected Files & Endpoints Endpoint: POST /api/v1/@apostrophecms/import-export/clean-export Route Definition: packages/import-export/lib/apiRoutes.js (lines 32–34) Method Implementation: packages/import-export/lib/methods/import.js (lines 1271–1324)

---

3. Root Cause Analysis In packages/import-export/lib/apiRoutes.js, the get.related handler explicitly validates that the caller is logged in: javascript get: { async related(req) { if (!req.user) { throw self.apos.error('forbidden'); } // ... } } In contrast, post.cleanExport (as well as post.overrideDuplicates) lacks any verification of req.user: javascript post: { async overrideDuplicates(req) { return self.overrideDuplicates(req); },

async cleanExport(req) { return self.cleanExport(req); // <-- No authentication check } } Because ApostropheCMS does not enforce authentication globally on all apiRoutes, omitting an explicit if (!req.user) guard allows anonymous requests to pass directly through to the business logic layer.

---

4. Evidence When sending an unauthenticated POST request with the site’s CSRF cookie (issued to any visitor on GET /), the request bypasses access control entirely and executes self.cleanExport(req), as demonstrated by the server stack trace:

text at Object.cleanExport (.../packages/import-export/lib/methods/import.js) at .../packages/apostrophe/modules/@apostrophecms/module/index.js:193:30 This confirms that execution directly reaches the core import-export handler without an authenticated session.

---

5. Impact 1. Broken Access Control: Unauthenticated users can invoke cleanup operations and delete temporary export files and artifacts stored on the server. 2. Unauthorized State Mutation: The endpoint allows modifying job records in the database via req.body.jobId (forcing them to ended: true, status: 'completed') and dismissing notifications via req.body.notificationId without verifying whether the resources belong to the requesting caller.

---

6. Suggested Remediation (Patch)

Enforce an authentication check in packages/import-export/lib/apiRoutes.js before executing the underlying methods:

diff --- a/packages/import-export/lib/apiRoutes.js +++ b/packages/import-export/lib/apiRoutes.js @@ -26,10 +26,16 @@ module.exports = self => { get: { ... }, post: { async overrideDuplicates(req) { + if (!req.user) { + throw self.apos.error('forbidden'); + } return self.overrideDuplicates(req); }, async cleanExport(req) { + if (!req.user) { + throw self.apos.error('forbidden'); + } return self.cleanExport(req); } }

Affected Software

1 affected componentFixes available
npm/@apostrophecms/import-export<3.7.1
3.7.1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@apostrophecms/import-export to a version that resolves this vulnerability.

    Fixed in 3.7.1
  2. Compensating control

    In packages/import-export/lib/apiRoutes.js, add an authentication guard before executing post.cleanExport: if (!req.user) { throw self.apos.error('forbidden'); } so unauthenticated requests cannot invoke self.cleanExport(req).

Event History

Oct 21, 2026
Advisory Published
via GitHub·05:13 PM
Data Sourced
via GitHub·05:13 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who can invoke the affected route?

Unauthenticated anonymous clients can invoke it after obtaining the standard CSRF cookie by visiting the site. The route does not verify that req.user is present before calling cleanExport.

2

What does an attacker need to exploit this?

The attacker needs network access to the POST endpoint and a standard CSRF cookie. No authenticated account is required.

3

How can I determine whether my deployment has this issue?

Inspect the clean-export POST route in packages/import-export/lib/apiRoutes.js. Affected code calls self.cleanExport(req) without checking req.user or otherwise enforcing authentication and authorization.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203