
Plane’s V2 asset subsystem vertraute Workspace-Slugs und Asset-UUIDs ohne die Durchsetzung der korrekten Mitgliedschaftsprüfungen, was einem authentifizierten Benutzer erlaubte, Assets in anderen Workspaces zu lesen, zu kopieren, zu löschen und zu überschreiben.
Das V2-Asset-Subsystem von Plane vertraute Workspace-Slugs und Asset-UUIDs, ohne die korrekten Mitgliedschaftsprüfungen durchzusetzen, was es einem authentifizierten Benutzer ermöglichte, Assets in anderen Workspaces zu lesen, zu kopieren, zu löschen und zu überschreiben.
Ich stieß auf dieses Problem, als ich Plane, die Open-Source-Projektmanagement-Plattform, mit einer sehr spezifischen Frage überprüfte:
Erzwingen die V2-Asset-Endpunkte tatsächlich Workspace-Grenzen, oder vertrauen sie zu sehr auf vom Angreifer bereitgestellte Workspace-Slugs und Asset-IDs?
In diesem Fall lautete die Antwort nein.
Das V2-Asset-Subsystem von Plane legte zwei zusammenhängende Autorisierungsfehler offen, die die Workspace-Isolation für jeden authentifizierten Benutzer durchbrachen:
Das machte Cross-Workspace-Asset-Missbrauch möglich.
In meinem validierten PoC konnte ein normaler Benutzer in Workspace Bravo:
Dieses Problem wurde später als CVE-2026-46558 zugewiesen.
Plane: Plane bei GitHub
CVE: CVE-2026-46558
Dies betraf Plane, das auf seiner offiziellen Website als von 50.000+ Teams weltweit genutzt beschrieben wird. Plane hebt zudem eine starke Open-Source-Adoption hervor, darunter 46.000+ GitHub-Sterne und 1.000.000+ Docker-Pulls, und zeigt Organisationen wie Tencent, Accenture, Microsoft und Amazon.
authenticated attacker in workspace B → workspace-level V2 asset route trusts target workspace slug and asset UUID without proper membership checks → presigned read / patch / delete against workspace A assets + duplicate-assets source lookup trusts uploaded source UUID → cross-workspace disclosure, copying, deletion, and branding overwrite
Plane ist eine Open-Source-Projektmanagement-Plattform, die zur Verwaltung von Folgendem verwendet wird:
Das bedeutet, dass sein Asset-Subsystem auf einer echten Vertrauensgrenze sitzt.
Die wichtige Frage hier war nicht, ob Plane Uploads unterstützt.
Die eigentliche Frage war:
Erzwingt Plane die Workspace-Isolation, wenn ein authentifizierter Benutzer auf Assets verweist, die einem anderen Workspace gehören?
In diesem Fall tat es das nicht.
Viele Bewertungen von Multi-Tenant-Anwendungen konzentrieren sich zuerst auf offensichtliche Admin-Endpunkte oder direkte Einstellungsaktualisierungen.
Das übersieht eine sehr verbreitete und reale Fehlerklasse:
sekundärer Objektzugriff über gemeinsame Datei- oder Asset-Subsysteme
Asset-Systeme sind leicht falsch zu implementieren, weil sie oft kombinieren:
Genau das ist die Art von Ort, an der Tenant-Grenzen leise schwächer werden.
Bei diesem Problem ging es nicht um Speicherbeschädigung. Es ging nicht um S3 selbst. Es ging nicht um die MIME-Verarbeitung von Uploads.
Es war ein Autorisierungs-Grenzfehler:
Das ist genug, um eine echte Schwachstelle zu erzeugen.
Ich bin nicht blind an Plane herangegangen, indem ich zufällige Endpunkte gefuzzt oder UUIDs ohne Modell erraten habe.
Der stärkere Ansatz bestand darin, zuerst die vielversprechendste Isolationsgrenze zu identifizieren.
Für Plane war das das V2-Asset-Subsystem.
Warum?
Weil ein gemeinsames Asset-System gefährlich wird, wenn:
Das war die richtige Grenze, die es zu untersuchen galt.
Und genau dort lebte der Fehler.
Es handelte sich eigentlich um zwei zusammenhängende Autorisierungsfehler im selben Subsystem.
Die Workspace-Level-Asset-Routen wurden durch Folgendes freigegeben:
apps/api/plane/app/urls/asset.py:50-56Die verwundbaren Handler befanden sich in:
apps/api/plane/app/views/asset/v2.py:314apps/api/plane/app/views/asset/v2.py:379apps/api/plane/app/views/asset/v2.py:400apps/api/plane/app/views/asset/v2.py:409Das Problem war einfach.
WorkspaceFileAssetEndpoint akzeptierte einen Workspace-Slug und eine Asset-UUID und löste dann direkt Objekte auf wie:
workspace = Workspace.objects.get(slug=slug)
und:
asset = FileAsset.objects.get(id=asset_id, workspace__slug=slug)
ohne zuerst sicherzustellen, dass der Aufrufer tatsächlich ein autorisiertes Mitglied dieses Ziel-Workspaces war.
Das bedeutete, dass der Endpunkt trotzdem Folgendes konnte:
für Objekte eines anderen Workspaces.
Die Route zum Duplizieren von Assets wurde abgebildet durch:
apps/api/plane/app/urls/asset.py:100-101Die verwundbare Logik befand sich in:
apps/api/plane/app/views/asset/v2.py:736-780Der Ziel-Workspace hatte einen Autorisierungsdekorator. Aber der Quell-Asset-Lookup hatte keinen.
Das Quellobjekt wurde geladen mit:
original_asset = FileAsset.objects.filter(id=asset_id, is_uploaded=True).first()
Das bedeutete, dass der Aufrufer nur benötigte:
Es gab keine Prüfung, ob der Aufrufer dem Quell-Workspace angehörte, dem das Asset tatsächlich gehörte.
Das ist der gesamte zweite Fehler.
Der wichtige Unterschied ist die Cross-Workspace-Auswirkung.
Viele Autorisierungsfehler werden heruntergespielt mit:
„es erfordert trotzdem eine Anmeldung“
Das verfehlt den Punkt.
Die eigentliche Frage ist nicht:
„Ist der Aufrufer authentifiziert?“
Die eigentliche Frage ist:
„Ist der Aufrufer für den spezifischen Workspace und das spezifische Asset, auf das eingewirkt wird, autorisiert?“
Bei Plane war diese Antwort nein.
Das verwandelt das, was wie eine gewöhnliche Objektbehandlung aussieht, in ein echtes Multi-Tenant-Sicherheitsproblem.
Es gibt einen klaren Unterschied zwischen:
Dieses Problem war eindeutig der zweite Fall.
Ich habe das Problem lokal gegen Plane Community Edition 1.2.3 validiert, mit zwei gewöhnlichen Benutzern in zwei nicht verwandten Workspaces:
alpha-20260323072017bravo-20260323072017Ich habe Alpha verwendet, um ein legitimes privates hochgeladenes Asset in einem Projektissue zu erstellen.
Die validierte private Asset-ID in meinem Durchlauf war:
6ed6ed62-d1b2-4399-8220-336c01b7d72c
Als Bravo forderte ich an:
GET /api/assets/v2/workspaces/alpha-20260323072017/6ed6ed62-d1b2-4399-8220-336c01b7d72c/
Plane antwortete:
HTTP/1.1 302 Found
mit einer presigned Download-URL für Alphas Asset.
Der Hash der heruntergeladenen Datei stimmte exakt mit Alphas ursprünglichem privaten Asset überein:
original: 0d4d070f550ba59ba6b30bee62343cf68ea221af7034f131f72f6409cf5a598e
unauthorized read: 0d4d070f550ba59ba6b30bee62343cf68ea221af7034f131f72f6409cf5a598e
Das bewies, dass der Lesepfad erfolgreich Workspace-Grenzen überschritt.
Als Bravo forderte ich dann an:
POST /api/assets/v2/workspaces/bravo-20260323072017/duplicate-assets/6ed6ed62-d1b2-4399-8220-336c01b7d72c/
Plane antwortete:
HTTP/1.1 200 OK
und erstellte ein dupliziertes Asset auf Angreiferseite:
72d51497-ccc1-4546-ba14-28fae5d37dbb
Die SHA-256 der duplizierten Datei stimmte exakt mit Alphas ursprünglichem Asset überein:
0d4d070f550ba59ba6b30bee62343cf68ea221af7034f131f72f6409cf5a598e
Das bewies, dass die Quell-Asset-UUID allein ausreichte, um Cross-Workspace-Inhalte in einen vom Angreifer kontrollierten Workspace zu kopieren.
Als Bravo sendete ich dann:
DELETE /api/assets/v2/workspaces/alpha-20260323072017/6ed6ed62-d1b2-4399-8220-336c01b7d72c/
Plane antwortete:
HTTP/1.1 204 No Content
Als Alpha später dieses Asset abrief, gab der Server zurück:
HTTP/1.1 404 Not Found
Das bewies eine Cross-Workspace-Integritätsauswirkung, nicht nur Offenlegung.
Als Bravo erstellte ich ein WORKSPACE_LOGO-Asset gegen Alphas Workspace über die verwundbare Workspace-Level-Asset-Route, lud vom Angreifer kontrollierte Inhalte hoch und finalisierte sie.
Danach zeigten Alphas Workspace-Metadaten auf das vom Angreifer kontrollierte Logo-Asset:
c1032f06-3cf5-4f7e-b139-e6976d8c567d
Der Hash des heruntergeladenen endgültigen Logos stimmte exakt mit der Angreifer-Nutzlast überein:
expected: b9d1ef1de88d61bf55dd18055839bacacb832a752e17a7312547f641113d0e7b
observed: b9d1ef1de88d61bf55dd18055839bacacb832a752e17a7312547f641113d0e7b
Das bewies einen sichtbaren Cross-Workspace-Überschreibungspfad, nicht nur ein verstecktes Backend-Zugriffsproblem.
Jedes einzelne der obigen Ergebnisse hätte bereits ausgereicht, um einen echten Fehlerbericht zu rechtfertigen.
Aber die Validierung der vollständigen Kette war aus zwei Gründen wichtig.
Es zeigte, dass das Problem nicht auf Nur-Lesen-Exposition beschränkt war.
Dieselbe schwache Grenze ermöglichte:
Das macht die Auswirkung viel stärker als eine enge „kann eine Datei abrufen“-IDOR.
Es zeigte, dass die beiden Codepfade zusammenhängen, aber unabhängig voneinander wichtig waren.
Ein Fehler legte Workspace-Level-Asset-Operationen direkt offen. Der zweite Fehler verwandelte hochgeladene Asset-UUIDs in eine wiederverwendbare Exfiltrationsprimitive durch Duplizierung.
Das machte die gesamte Sicherheitsgeschichte viel schwerer abzutun.
Die sichtbarste Überschreibungsauswirkung, die ich validierte, war:
WORKSPACE_LOGODas war bewusst, weil es einfach zu überprüfen ist und einen offensichtlichen Cross-Tenant-Integritätsfehler demonstriert.
Aber der Endpunkt war nicht auf Workspace-Logos beschränkt.
Der verwundbare Workspace-Level-Asset-Fluss akzeptierte auch mehrere Entitätskontexte, darunter:
Das war wichtig, weil es zeigte, dass der Fehler strukturell war und nicht an ein einzelnes Branding-Feld gebunden.
Ich habe den Workspace-Logo-Pfad direkt validiert. Der breitere Codepath deutete stark darauf hin, dass zusätzliche Asset-gestützte Kontexte demselben Autorisierungsfehler ausgesetzt waren.
Dieses Problem wurde zu Recht als Hoch eingestuft.
Die Advisory-Klassifizierung war:
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L
Diese Klassifizierung ergibt Sinn.
Die Behauptung ist nicht, dass ein nicht authentifizierter Angreifer Plane aus dem Nichts kompromittieren kann. Die Behauptung ist, dass jeder normale authentifizierte Benutzer im V2-Asset-Subsystem Tenant-Grenzen überschreiten und hochwirksame Asset-Operationen gegen andere Workspaces durchführen kann.
Das ist eine echte und verteidigungsfähige Multi-Tenant-Autorisierungsschwachstelle.
Manche Leute unterschätzen authentifizierte Cross-Tenant-Fehler, weil sie hören:
„der Angreifer brauchte bereits ein Konto“
Das ist keine ernsthafte Verteidigung.
In Multi-Workspace-Software sollen normale authentifizierte Benutzer innerhalb ihres eigenen Autorisierungsbereichs eingeschlossen sein.
Wenn ein Benutzer mit niedrigen Rechten in Workspace Bravo Objekte in Workspace Alpha lesen, kopieren, löschen oder überschreiben kann, dann ist die Workspace-Isolation gebrochen.
Genau das ist die Sicherheitseigenschaft, die die Anwendung schützen soll.
Besonders in einer Projektmanagement-Plattform, die interne Arbeitsinhalte und Branding-Assets speichert, ist das ein bedeutendes Problem mit echten Auswirkungen auf Vertraulichkeit und Integrität.
Das Problem wurde in Plane v1.3.1 behoben.
Die Versionshinweise für v1.3.1 beschrieben den Fix klar:
@allow_permission zu allen WorkspaceFileAssetEndpoint-Methoden hinzuDuplicateAssetEndpoint auf Workspaces, in denen der Aufrufer ein aktives Mitglied istDas ist die richtige Korrekturrichtung, da sie beide fehlgeschlagenen Sicherheitseigenschaften adressiert:
Das ist genau das, was dieser Fehler brauchte.
Ein guter Fix besteht hier nicht darin, UUIDs besser zu verstecken. Es geht nicht darum, die Presigned-URL-Generierung zu ändern.
Es geht darum, die korrekte Regel wiederherzustellen:
Workspace-Slug plus Asset-UUID dürfen niemals ausreichen, ohne eine auf den aktuellen Benutzer bezogene Autorisierung
Das ist der Teil, den der Patch wiederhergestellt hat.
Dieses Problem wurde privat über GitHub Security Advisories gemeldet.
Der Bericht enthielt:
Das Problem wurde später veröffentlicht als:
Das Advisory wurde am 15. Mai 2026 veröffentlicht. Der Fix wurde in Plane v1.3.1 ausgeliefert.
Die wichtigste Lektion hier ist einfach:
Gemeinsame Asset-Subsysteme sind Autorisierungsgrenzen, nicht nur Speicherhilfen
Viele Entwickler denken in Begriffen von:
Diese Dinge sind Implementierungsdetails.
Die eigentliche Sicherheitsfrage ist:
Wer ist berechtigt, dieses Asset über Tenant-Grenzen hinweg aufzulösen, zu mutieren, zu kopieren oder neu zu verknüpfen?
Bei Plane wurde diese Grenze nicht konsistent durchgesetzt.
Das ist die eigentliche Erkenntnis.
Dieser Fehler unterstreicht auch etwas Wichtiges bei der Überprüfung von Multi-Tenant-Anwendungen:
Diese Schwachstelle betraf kein exotisches Speicherverhalten.
Es ging darum, die richtige Frage zur Vertrauensgrenze zu stellen.
Bei Plane konnte ein authentifizierter Benutzer den Slug eines anderen Workspaces und Asset-UUIDs angeben, und das V2-Asset-Subsystem vertraute diesen Identifikatoren weiter, als es sollte.
Deshalb wurde dies zu CVE-2026-46558.
Behoben in Plane v1.3.1.