Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-19264 — CVE-2026-19264 – Kritische, nicht authentifizierte Path-Traversal-Schwachstelle bis hin zur vollständigen Übernahme der Instanz in Postiz (< 2.22.1). Technischer Bericht: Decode-Order-Bypass, JWT_SECRET-Eskalation und Analyse des Upstream-Fixes. | Kitploit
Tools/GitHubGitHub/darklycn1976/cve-2026-19264
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationWebsicherheitLernen & Bildung
GitHubdarklycn1976/cve-2026-19264

CVE-2026-19264

CVE-2026-19264 – Kritische, nicht authentifizierte Path-Traversal-Schwachstelle bis hin zur vollständigen Übernahme der Instanz in Postiz (< 2.22.1). Technischer Bericht: Decode-Order-Bypass, JWT_SECRET-Eskalation und Analyse des Upstream-Fixes.

Repository anzeigenWebseite
8vor 1 MonatNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-19264 – Nicht authentifizierte Path Traversal bis zur vollständigen Übernahme der Instanz in Postiz

CVE-2026-19264 – Nicht authentifizierte Path Traversal bis zur vollständigen Übernahme der Instanz in Postiz

Autor: Krithik Babu P (@DarkLycn1976) Veröffentlicht: 2026-08-10 CVE: CVE-2026-19264 Schweregrad: Kritisch – CVSS 4.0 9.3 / CVSS 3.1 9.8 CWE: CWE-22 – Unzulässige Beschränkung eines Pfadnamens auf ein eingeschränktes Verzeichnis Betroffen: gitroomhq/postiz-app < 2.22.1 Behoben in: v2.22.1


TL;DR

Postiz stellte lokal gespeicherte Medien über eine Route bereit, die vom Aufrufer gelieferte Pfadsegmente mit dem Upload-Verzeichnis verknüpfte und das Ergebnis zurückschickte – ohne Pfadnormalisierung, ohne Containment-Prüfung und ohne Authentifizierung.

Das naheliegende Traversal-Payload liefert 404, weil Next.js die ../-Segmente vor dem Routing zusammenfaltet. Aber URL-kodierte Separatoren überstehen das Route-Matching und werden auf dem Weg zum Dateisystem-Aufruf genau einmal zusätzlich dekodiert, wodurch die Traversal jenseits aller Prüfungen wiederhergestellt wird.

Ein nicht authentifizierter Angreifer konnte jede Datei lesen, die für den Anwendungsprozess lesbar ist – einschließlich dessen Umgebung, die das JWT-Signaturgeheimnis enthält. Da Postiz Sitzungstokens mit diesem Geheimnis signiert und ohne Ablauf-Claim ausstellt, macht das Wiedererlangen des Geheimnisses aus einer Datei-Leseprimitive eine dauerhafte, fälschbare Sitzung als beliebiger Benutzer, einschließlich eines Administrators.

Ein einziger nicht authentifizierter GET-Request führt zur vollständigen Übernahme der Instanz.


1. Hintergrund

Postiz ist eine Open-Source-Plattform zur Planung von Social-Media-Beiträgen – zum Zeitpunkt des Schreibens rund 34.000 GitHub-Sterne – aufgebaut als Next.js-Frontend mit einem NestJS-Backend. Sie wird häufig von Agenturen und kleinen Teams selbst gehostet, um verbundene Social-Media-Konten, geplante Inhalte und Abrechnung zu verwalten.

Selbst gehostete Installationen können hochgeladene Medien lokal statt in einem Objektspeicher ablegen. Dieses Verhalten wird durch eine einzige Umgebungsvariable gesteuert:

STORAGE_PROVIDER=local

Dies ist der Wert, der in .env.example ausgeliefert wird. Die meisten Selbst-Hoster betreiben also genau diese Einstellung, sofern sie nicht bewusst S3 oder Cloudflare R2 konfigurieren.

2. Die Angriffsfläche

Wenn lokaler Speicher aktiv ist, schreibt next.config.js den öffentlichen Pfad /uploads/:path* auf eine interne API-Route um:

apps/frontend/src/app/(app)/api/uploads/[[...path]]/route.ts

Zwei Eigenschaften machen diese Route interessant, bevor überhaupt ein Bug im Spiel ist:

  1. Sie ist nicht authentifiziert. Keine Frontend-Middleware schützt sie. Die Auslieferung öffentlicher Medien ist beabsichtigt, daher ist keine Sitzung erforderlich.
  2. Sie ist ein Catch-all. Das optionale Catch-all-Segment [[...path]] bedeutet, dass jede verbleibende Pfadkomponente als Array ankommt, das der Handler frei interpretieren kann.

Wenn STORAGE_PROVIDER etwas anderes als local ist, zeigt die Rewrite-Regel auf /404 und der Handler ist unerreichbar. Dieses Konfigurations-Gate ist das Einzige, was zwischen einer Installation und diesem Bug steht.

3. Der verwundbare Code

Der Handler vor v2.22.1:

export const GET = async (request: NextRequest, context) => {
  const { path } = await context.params;
  const filePath =
    process.env.UPLOAD_DIRECTORY + '/' + (path ?? []).join('/');

  const response  = createReadStream(filePath);
  const fileStats = statSync(filePath);
  // ... stream the file back to the caller
};

Drei Defekte in vier Zeilen:

  • Keine Normalisierung. path.normalize(), path.resolve() – keine von beiden wird aufgerufen. Welche Segmente auch immer ankommen, sie werden unverändert konkateniert.
  • Keine Containment-Prüfung. Nichts verifiziert, dass der resultierende filePath weiterhin innerhalb von UPLOAD_DIRECTORY liegt.
  • String-Konkatenation statt Pfad-Verknüpfung. + '/' + behandelt die Komponenten als Text, nicht als Pfad mit Semantik.

Das Ergebnis geht direkt in createReadStream() und die Bytes werden mit einem aus dem Dateinamen abgeleiteten MIME-Typ an den Aufrufer gestreamt. Es gibt weder eine Allow-Liste für Erweiterungen noch einen Inhaltsfilter.

4. Warum das naheliegende Payload scheitert

Der Lehrbuch-Angriff lautet:

GET /uploads/../../../etc/passwd

Bei Postiz liefert dies 404, und genau diese 404 ist der gesamte Grund, warum dieser Bug überleben konnte, bis er gefunden wurde.

Next.js normalisiert den Request-Pfad während des Routings. Rohe ../-Segmente werden zusammengefaltet, bevor der Router entscheidet, welcher Handler aufgerufen wird. Wenn der Request den Catch-all erreicht, ist die Traversal bereits eliminiert – entweder löst der Pfad zu einer Stelle auf, für die keine passende Route existiert, oder er löst zurück in /uploads auf, wobei die Punkt-Segmente verschwunden sind.

Für jemanden, der schnell testet, liest sich diese 404 wie „das Framework kümmert sich darum". Sie ist eine echte, funktionierende Verteidigung. Das Problem ist nicht, dass sie fehlt, sondern wo in der Pipeline sie greift.

5. Der Bypass – ein Konflikt bei der Decodierungsreihenfolge

Route-Matching und Request-Handler führen nicht dieselbe Anzahl an Prozent-Decodierungs-Durchläufen durch.

Wenn die Separatoren prozentkodiert sind, ist die Sequenz während des Route-Matchings kein Pfadseparator. %2e%2e%2f ist nur ein opaker String – inerter Text, den der Normalisierer nicht anzufassen braucht. Sie segelt unversehrt durch das Routing, wird vom Catch-all gematcht und auf dem Weg in die params des Handlers dekodiert, wo sie wieder zu ../ wird.

An diesem Punkt wird sie an UPLOAD_DIRECTORY konkateniert und an createReadStream() übergeben – vorbei am Routing, vorbei an der Normalisierung, vorbei an jeder Kontrolle, die sie gestoppt hätte.

Funktionierende Formen:

GET /uploads/%2e%2e%2fsecretdir%2fsecret.txt        → 200, file outside the upload directory
GET /uploads/..%2f..%2f..%2fetc%2fpasswd            → 200
GET /uploads/%2e%2e%2f%2e%2e%2f...%2fetc%2fpasswd   → 200, returned the real /etc/passwd

Doppelte Kodierung funktioniert nicht – %252e bleibt beim einzelnen Decodierungsdurchlauf literal und wird nie zu einem Punkt. Genau eine Kodierungsebene ist der Sweet Spot – eine nützliche Erinnerung daran, dass „stärker kodieren" keine Strategie ist.

Die Invariante, an der man festhalten sollte:

Eine Kontrolle, die ausgeführt wird, bevor die Decodierung abgeschlossen ist, schützt den Sink nicht.

6. Eskalation – vom beliebigen Lesen zur Übernahme der Instanz

Eine Datei-Leseprimitive ist für sich genommen bereits Hoch. Was dies zu Kritisch macht, ist das, was sie erreicht.

Schritt 1 – die Umgebung auslesen. Die eigene Konfiguration des Node-Prozesses liegt im Installationsverzeichnis auf der Platte. .env liefert unter anderem:

  • JWT_SECRET – den Signaturschlüssel für Sitzungstokens
  • DATABASE_URL – vollständige Postgres-Zugangsdaten
  • OAuth-Geheimnisse verbundener Anbieter und Abrechnungsschlüssel

Schritt 2 – eine Sitzung fälschen. Postiz signiert Sitzungstokens mit JWT_SECRET per HS256 über jsonwebtoken. Entscheidend ist: Tokens werden ohne expiresIn ausgestellt, ein gefälschtes Token ist also unbegrenzt gültig.

Tool herunterladen