ApostropheCMS import-export tar guard misses './..' because it is a literal '../' substring test
Zusammenfassung
Der Tar-Extraktionsschutz, der in @apostrophecms/import-export für GHSA-mwxc-m426-3f78 hinzugefügt wurde, ist eine literale Teilstring-Prüfung auf ../, und ./.. enthält diesen Teilstring nicht. Ein Archiveintrag namens ./.. passiert daher die Überprüfung, path.join normalisiert ihn auf das übergeordnete Verzeichnis des Exportverzeichnisses, und der resultierende fs.WriteStream öffnet ein Verzeichnis und gibt EISDIR ohne registrierten error-Listener aus, was den Node-Prozess beendet.
Bestätigt auf default-branch HEAD 1bd5d0a7a6fe880836fa75adad6964f1c577d640, Paketversion 3.6.2.
Details
packages/import-export/lib/formats/gzip.js, im Tar-Stream-Handler entry innerhalb von extract(filepath, exportPath):
const name = header.name.replace(/\\/g, '/');
if (name.includes('../')) {
// skipped
}
...
stream.pipe(fs.WriteStream(path.join(exportPath, name)));
In diesen vier Zeilen liegen zwei separate Probleme. Die Schutzprüfung testet den rohen Eintragsnamen auf einen Teilstring, anstatt den zusammengefügten Pfad aufzulösen und eine Pfadgrenzenprüfung (Containment) zu erzwingen; zudem verfügt der Schreib-Stream über keinen error-Handler, sodass jeder Stream-Fehler zu einem unbehandelten 'error'-Ereignis wird.
Um die Schwachstelle zu erreichen, ist lediglich ein Konto mit Importberechtigung erforderlich. packages/import-export/modules/@apostrophecms/import-export-page/index.js stellt post.importExportImport bereit, das lib/methods/import.js aufruft; dieser Handler erfordert req.user und ruft danach format.input(exportPath) auf, was für einen .gz-Upload darin besteht, dass gzip.js die Funktion extract() auf das hochgeladene Archiv anwendet.
PoC
Hierbei handelt es sich nicht um einen End-to-End-Exploit. Im Folgenden werden die drei Primitiven aufgeführt, von denen der Absturz abhängt, jeweils einzeln ausgeführt, zusammen mit einem Trace der Route auf Quellcodeebene. Die Kette von post.importExportImport bis extract() wurde im Quellcode nachvollzogen, nicht live beobachtet.
Der Schutz übersieht die Payload:
node -e "console.log('./..'.includes('../')); console.log('..'.includes('../')); console.log('a/./..'.includes('../'));"
false
false
false
path.join löst den Pfad anschließend außerhalb des Exportverzeichnisses auf:
node -e "const path=require('path'); const exportPath='/tmp/exportRoot'; console.log(path.join(exportPath,'./..'));"
/tmp
Und ein Schreib-Stream, der auf einem Verzeichnis ohne error-Listener geöffnet wird, beendet den Prozess, anstatt die Anfrage fehlschlagen zu lassen:
node -e "const fs=require('fs'); const s=fs.createWriteStream('/tmp'); s.write('x'); s.end(); setTimeout(()=>console.log('still alive'),500);"
events.js:291
throw er; // Unhandled 'error' event
^
Error: EISDIR: illegal operation on a directory, open '/tmp'
Emitted 'error' event on WriteStream instance at:
at internal/fs/streams.js:361:12
at FSReqCallback.oncomplete (fs.js:156:23) {
errno: -21,
code: 'EISDIR',
syscall: 'open',
path: '/tmp'
}
Der Frame events.js:291 zeigt, dass die Ausgabe von der Node-14-Zeile des Testsystems stammt. Das Verhalten bei unbehandelten error-Ereignissen ist nicht versionsspezifisch, die genaue Fehlermeldung auf den jeweils unterstützten Node-Versionen sollte jedoch geprüft werden.
Bestätigung auf Quellcodeebene ohne Programmausführung:
grep -n "includes('../')" packages/import-export/lib/formats/gzip.js
grep -n "WriteStream" packages/import-export/lib/formats/gzip.js
Auswirkungen
Ein authentifizierter Benutzer mit Zugriff auf die Import-Benutzeroberfläche kann ein manipuliertes Archiv hochladen und den verarbeitenden Node-Prozess zum Absturz bringen. Jeder Worker-Prozess, der ein solches Archiv verarbeitet, stürzt auf die gleiche Weise ab.
Vorgeschlagene Behebung
Das Ziel auflösen, die Pfadeingrenzung erzwingen und einen Fehler-Handler anfügen:
const base = path.resolve(exportPath);
const target = path.resolve(path.join(exportPath, name));
if (target !== base && !target.startsWith(base + path.sep)) {
stream.on('end', next);
stream.resume();
return;
}
if (header.type === 'directory') {
fsp.mkdir(target).then(next).catch(reject);
} else {
const out = fs.WriteStream(target);
out.on('error', reject);
stream.pipe(out);
stream.on('end', next);
}
Der Error-Handler ist unabhängig davon sinnvoll: Jeder Tar-Eintrag, der auf einem bestehenden Verzeichnisnamen landet, hat denselben Effekt, unabhängig davon, ob eine Pfadüberquerung vorliegt.
Warum dies nicht GHSA-mwxc-m426-3f78 ist
Die Überprüfung name.includes('../') ist die Fehlerbehebung, die für GHSA-mwxc-m426-3f78 / CVE-2026-32731 bereitgestellt wurde. Sie blockiert Namen, die die literale Zeichenfolge ../ enthalten. Sie kanonisiert jedoch nicht den zusammengefügten Pfad, sodass ./.. und ein einfaches .. weiterhin passieren, und sie behebt nicht den fehlenden error-Listener. Dieser Bericht befasst sich mit den verbleibenden Lücken der Teilstring-Prüfung.
KI-Unterstützung wurde für das Code-Audit und die Ausarbeitung verwendet. Die genauen Guard- und WriteStream-Zeilen in packages/import-export/lib/formats/gzip.js beim angegebenen HEAD wurden manuell verifiziert, die Import-Route vom Seitenmodul über lib/methods/import.js in den Eintrags-Handler wurde manuell nachverfolgt und die drei Node-Einzeiler wurden manuell ausgeführt und wortwörtlich übernommen.
Was zu tun ist
Aktualisieren Sie @apostrophecms/import-export auf Version 3.7.0 oder höher.
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| npm-Paket | @apostrophecms/import-export | < 3.7.0 | 3.7.0 |
Verweise
- https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-97wv-p4xx-c7mg
- 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/@apostrophecms/import-export@3.7.0
- CVSS-Vektor
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N- Schwäche (CWE)
CWE-22- Plattform
- npm
- Paket
@apostrophecms/import-export- Veröffentlicht
- 20.10.2026
- Aktualisiert
- 20.10.2026 21:35
Quellen und Lizenzen · Von DockRay bearbeitet oder übersetzt; Rechte und Lizenzen der Quellen bleiben erhalten.
OSV / GitHub Advisory Database - GHSA-97wv-p4xx-c7mg - CC BY 4.0
Schwachstellenhistorie: @apostrophecms/import-export
Alle veröffentlichten Schwachstellen dieses Pakets (npm-Paket), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
- Einträge insgesamt
- 4
- Erste → letzte
- 03.2026 10.2026
- Ohne Fix
- 0
- In Angriffen ausgenutzt
- 0
Verteilung nach Schweregrad
- Kritisch 1
- Mittel 3
Veröffentlichungen pro Jahr
- 2026: 4
-
ApostropheCMS import-export tar guard misses './..' because it is a literal '../' substring test dieser Eintrag
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.