
Penpots Fernbildimport ermöglichte es einem authentifizierten Dateibearbeiter, eine normale Medienkomfortfunktion in ein SSRF mit Backend-Ursprung zu verwandeln, da vom Angreifer kontrollierte URLs in einen Redirect-folgenden Server-Fetch-Pfad ohne Ziel-Filterung gelangten.
Penpots Remote-Bildimport erlaubte einem authentifizierten Datei-Editor, eine normale Medien-Komfortfunktion in einen Backend-originierten SSRF zu verwandeln, da vom Angreifer kontrollierte URLs einen Weiterleitungen folgenden Server-Abrufpfad ohne Ziel-Filterung erreichten.
Ich habe diesen Fehler beim Überprüfen von Penpot, der quelloffenen Design- und Code-Kollaborationsplattform, mit einer sehr spezifischen Frage gefunden:
Was passiert, wenn ein kollaboratives Designtool einem Benutzer erlaubt, dem Backend eine Remote-Bild-URL zu übergeben, um sie abzurufen?
In diesem Fall führte diese Frage zu einem echten Bug.
Der Remote-Bildimport-Ablauf von Penpot akzeptierte eine benutzergesteuerte URL und veranlasste das Backend, sie aus dem Server-Netzwerkkontext abzurufen, ohne Einschränkungen für Loopback- oder private Netzwerkziele durchzusetzen. Der gemeinsam genutzte HTTP-Client folgte auch automatisch Weiterleitungen.
Dadurch wurde eine normale Medien-Komfortfunktion in eine authentifizierte Backend-originierte SSRF-Grundlage verwandelt und führte schließlich zu CVE-2026-45806.
Penpot: Penpot auf GitHub
CVE: CVE-2026-45806
CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Dies betraf Penpot. Auf seiner offiziellen Website und im Medienkit präsentiert sich Penpot als mit einer +1 Millionen wachsenden Benutzerbasis und sagt, dass Zehntausende von Organisationen es nutzen, darunter Blender, Mozilla, Fedora, NTT Data, MIT, Société Générale, Cisco, Fujitsu, Indra und ByteDance.
authentifizierter Datei-Editor -> vom Angreifer kontrollierte Remote-Bild-URL -> create-file-media-object-from-url -> Backend download-image Abruf mit aktivierten Weiterleitungen -> finale Anfrage landet auf internem Nur-Bild-Endpunkt -> Backend-origin SSRF / interne Erreichbarkeit
Penpot ist eine quelloffene Design- und Code-Kollaborationsplattform.
Es behandelt Dinge wie:
Das bedeutet, dass sein Medienimportpfad auf einer echten Vertrauensgrenze liegt.
Die wichtige Frage war hier nicht, ob Penpot das Importieren von Remote-Bildern unterstützt.
Die eigentliche Frage war:
Schränkt Penpot ein, wohin das Backend eine Verbindung herstellen darf, wenn ein Benutzer ein Remote-Bild importiert?
In diesem Fall tat es das nicht.
Viele Leute unterschätzen Remote-Importfunktionen.
Das ist ein Fehler.
In dem Moment, in dem eine Anwendung:
schafft sie eine echte ausgehende Vertrauensgrenze.
Das war hier das Problem.
Dieser Fehler lag nicht im Bild-Rendering. Er lag nicht in der Dateispeicherung. Er lag nicht in den üblichen Berechtigungsprüfungen zum Bearbeiten einer Datei.
Es war ein klassischer serverseitiger Vertrauensfehler:
Das reicht aus, um eine echte Sicherheitslücke zu schaffen.
Ich bin nicht blind an Penpot herangegangen, indem ich zuerst zufällige RPC-Methoden gefuzzt oder nach Abstürzen gesucht habe.
Der stärkere Ansatz war, die vielversprechendste Sicherheitsgrenze zu identifizieren.
Für Penpot war das der Remote-Medienimport.
Warum?
Weil diese Funktion kombiniert:
Das war die richtige Grenze zu überprüfen.
Und genau dort lebte der Fehler.
Der Fehler reduziert sich auf eine kleine Vertrauenskette.
Im Frontend:
(defn upload-media-url
[name file-id url]
(rp/cmd!
:create-file-media-object-from-url
{:name name
:file-id file-id
:url url
:is-local true}))
die vom Benutzer kontrollierte url wird direkt in den RPC-Aufruf gesendet.
Dann im Backend:
(sv/defmethod ::create-file-media-object-from-url
...
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}]
(files/check-edition-permissions! pool profile-id file-id)
...
(let [_ (files/get-minimal-file cfg file-id)
mobj (create-file-media-object-from-url cfg (assoc params :profile-id profile-id))])
und:
(defn- create-file-media-object-from-url
[cfg {:keys [url name] :as params}]
(let [content (media/download-image cfg url)
das Backend überprüft, ob der Aufrufer die Zieldatei bearbeiten darf, und übergibt dann die vom Angreifer kontrollierte URL an media/download-image.
Die Abruf-Implementierung ist hier:
(defn download-image
"Download an image from the provided URI and return the media input object"
[{:keys [::http/client]} uri]
...
(http/req! client
{:method :get :uri uri}
{:response-type :input-stream})
Und der gemeinsam genutzte HTTP-Client ist konfiguriert als:
(http/build-client {:connect-timeout 30000
:follow-redirects :always}))
Das ist die gesamte Schwachstelle:
Weil der Angreifer nur benötigt:
Die Angriffskette ist unkompliziert:
Das ist der gesamte Fehler.
Der wichtige Unterschied ist wo die Anfrage stattfindet.
Die Frage ist nicht:
„Kann Penpot Bilder von URLs importieren?"
Die eigentliche Frage ist:
„Kann ein authentifizierter Benutzer das Penpot-Backend dazu bringen, eine Verbindung zu internen Zielen herzustellen, die der Benutzer nicht über die Anwendung erreichen können sollte?"
In diesem Fall war die Antwort ja.
Das ist wichtig, weil es einen echten Unterschied gibt zwischen:
Bildvalidierung hebt diesen Unterschied nicht auf.
Sie schränkt einige direkte Exfiltrationsfälle ein, hebt aber nicht die SSRF-Bedingung oder den Netzwerkgrenzenbruch auf.
Ich habe dieses Problem mit einem kontrollierten lokalen Proof validiert, der direkt mit dem überprüften Penpot-Codepfad verbunden ist.
Das Ziel war nicht, die Infrastruktur Dritter zu treffen. Das Ziel war, die genaue Sicherheitseigenschaft zu beweisen: