← Alle Beiträge

Summer ’26 Apex

Apex startet ab Summer ’26 im User Mode

Zwei Standardwerte drehen sich um: Datenbankoperationen prüfen künftig Feldberechtigungen, und Klassen erzwingen Sharing-Regeln. Beides gilt für Code, der gegen API-Version 67.0 kompiliert wird.

Was sich ändert

Apex lief bisher im Systemkontext: Objektrechte, Field-Level Security und Sharing-Regeln des ausführenden Benutzers waren beim Datenzugriff schlicht nicht wirksam. Wer sie berücksichtigen wollte, musste das ausdrücklich hinschreiben. Mit API-Version 67.0 dreht Salesforce zwei dieser Voreinstellungen um:

Bereich Bisher Ab API 67.0
SOQL, SOSL, DML, Database-Methoden System Mode: FLS und Objektrechte werden ignoriert User Mode: FLS, Objektrechte und Sharing greifen
Klassendeklaration ohne Schlüsselwort verhält sich wie without sharing verhält sich wie with sharing
WITH SECURITY_ENFORCED gebräuchlicher Zusatz in SOQL zurückgezogen, WITH USER_MODE tritt an die Stelle

Bestehender Code läuft weiter. Apex-Verhalten ist an die API-Version der Klasse gebunden. Eine Klasse, die auf Version 66.0 oder früher steht, verhält sich unverändert. Die neuen Standardwerte greifen erst, wenn du die Version anhebst, was in der Regel dann passiert, wenn jemand die Klasse ohnehin anfasst.

Warum der Schritt richtig ist

Der alte Standard war eine Fehlerquelle mit Ansage: Sicherheit war Opt-in, und wer das Schlüsselwort vergaß, bekam stillschweigend die unsichere Variante. Die Salesforce-Dokumentation benennt das seit Jahren offen: ohne inherited sharing oder with sharing werden auch Datensätze angezeigt, für die der Benutzer keine Freigabe hat, und zwar wegen des unsicheren Standardverhaltens. Ein Standardwert, dessen Vergessen ein Sicherheitsloch erzeugt, ist der falsche Standardwert.

Dieselbe Logik gilt für FLS. Salesforce empfiehlt schon länger, Feldberechtigungen über WITH USER_MODE statt über WITH SECURITY_ENFORCED zu erzwingen, und die Gründe sind handfest:

Was das praktisch bedeutet

Integrationsbenutzer brauchen echte Berechtigungen

Das ist der Punkt, der am häufigsten weh tut. Batch-Jobs, Queueables und Integrations-Endpunkte liefen bisher davon, dass der Systemkontext alles durchwinkt. Sobald der Code im User Mode läuft, braucht der ausführende Benutzer die Objekt- und Feldrechte tatsächlich; als Permission Set, nicht als Annahme. Für Automated-Process-Benutzer gilt das ausdrücklich ebenfalls: ohne explizit zugewiesene Permission Sets können sie die Prüfungen nicht bestehen.

Trigger bleiben im Systemkontext

Trigger sind von der Umstellung ausgenommen. Sie umgehen Sharing und FLS weiterhin einheitlich und können keinen Zugriffsmodus deklarieren. Das ist konsequent, denn ein Trigger ist Plattformlogik und keine Benutzeraktion. Es verschiebt die Verantwortung aber in die Service-Klassen dahinter.

Wo du bewusst im System Mode bleiben willst

Es gibt legitime Fälle: eine Genehmigungslogik, die Datensätze prüfen muss, die der Antragsteller nicht sehen darf; eine Aggregation über alle Regionen für ein Reporting. Dafür schreibst du den Modus künftig hin, statt ihn zu erben:

// Ausdrücklich im Systemkontext, mit Begründung im Code
List<Case> alle = [SELECT Id, OwnerId FROM Case WITH SYSTEM_MODE];

Database.insert(datensaetze, AccessLevel.SYSTEM_MODE);

Umgekehrt lässt sich User Mode auch punktuell erzwingen, solange die Klasse noch auf einer älteren API-Version steht: über WITH USER_MODE in der Abfrage oder insert as user beziehungsweise AccessLevel.USER_MODE bei DML.

stripInaccessible bleibt nützlich

Wenn eine Exception die falsche Antwort ist, etwa bei einem Formular, das auch mit eingeschränkten Feldrechten funktionieren soll, ist Security.stripInaccessible() weiterhin das passende Werkzeug. Es entfernt unzugängliche Felder aus Ergebnissen oder vor einem DML, statt den Vorgang abzubrechen, und eignet sich außerdem zum Bereinigen von Objekten, die aus einer nicht vertrauenswürdigen Quelle deserialisiert wurden.

Ein Vorgehen für bestehende Orgs

  1. Nicht alles auf einmal hochziehen. Die API-Version pro Klasse anheben, nicht per Skript über das ganze Repo. Der Sprung ist ein Verhaltenswechsel, kein Formalakt.
  2. Mit den Integrationsbenutzern anfangen. Prüfen, welche Permission Sets sie tatsächlich haben. Fast immer ist das die Lücke.
  3. Tests gegen echte Benutzerkontexte laufen lassen. System.runAs() mit einem Benutzer, der dem Produktivprofil entspricht. Ein Test als Administrator beweist hier nichts.
  4. Verbliebene WITH SECURITY_ENFORCED ersetzen. Und dabei nicht beides mischen: Salesforce rät ausdrücklich davon ab, Zugriffsmodi und den alten Zusatz in derselben Abfrage zu kombinieren.

Quellen