GHSA-rw26-wwfc-9wvm
ApostropheCMS: Missing Authentication in `cleanExport` Route
Packages
| Ecosystem | Package | Affected | Fixed in |
|---|---|---|---|
| npm | @apostrophecms/import-export | < 3.7.1 | 3.7.1 |
Details
As written in the advisory (Markdown source, shown as plain text).
#### 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);
}
}
```
References
External links from the advisory. They lead to third-party sites.
- https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-rw26-wwfc-9wvm
- https://nvd.nist.gov/vuln/detail/CVE-2026-113648
- https://github.com/apostrophecms/apostrophe/commit/06e4b377f3c360f9e89c32dccd7e505ad5ddf498
- https://github.com/apostrophecms/apostrophe/commit/40b989b1a9dd23d30029b8ce7668634265cfe5ea
- https://github.com/apostrophecms/apostrophe
- https://github.com/apostrophecms/apostrophe/releases/tag/@apostrophecms/[email protected]