
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-20260323072017