If your AppExchange package runs anonymous Apex in a subscriber org, Summer ’27 is your deadline. The Summer ’26 release notes ship a release update called “Block Apex Anonymous Code Execution from Managed Packages,” and it does exactly what the name says.
What’s actually changing
For years, a common trick let packaged code reach outside its own walls: call UserInfo.getSessionId() from inside your package, grab the session ID, and use it to call the SOAP or REST executeAnonymous endpoint. From there, you could run whatever Apex you wanted, including code that was never part of your package metadata.
Salesforce is shutting that down. Once the release update is on, a managed package session can no longer authenticate an executeAnonymous call. You get this back instead:
Managed package sessions are not authorized to call executeAnonymous.
It applies to both 1GP and 2GP packages, and enforcement lands in Summer ’27.
There’s a sharper edge for new development. Any namespace you create in Summer ’26 or later is blocked from anonymous Apex no matter what, whether or not the subscriber flips the release update. So a fresh package can’t lean on this pattern at all. Existing packages get the toggle and the runway until Summer ’27.
Why Salesforce cares
The reasoning, spelled out in the notes, is fair enough. Anonymous Apex isn’t versioned, isn’t logged, and skips the normal access controls. When a package can execute arbitrary code through a session ID, the subscriber has no real record of what ran in their org or under what permissions. That’s a security hole, and it’s exactly the kind of thing a security review is supposed to catch.
The fix Salesforce wants: put all your Apex in your package metadata so it runs as versioned, logged, permission-aware code. When you need to call into the subscriber’s own code, do it through a supported contract instead of a code-injection back door.
The part that trips people up
Not every “we call executeAnonymous” setup is the same, and the difference matters.
The block targets the managed package session specifically, the one you get from getSessionId() inside packaged Apex. If your integration authenticates a different way, say an external service using a connected app with an OAuth refresh token, the token it gets is a normal user session, not a managed package session. On the face of it, that flow isn’t what this update describes.
I’d still test it rather than trust the reading. Spin up a scratch or dev org, install the package, turn the release update on from Setup, and run your real flow end to end. If it still works with the toggle enabled, you’re clear. If your connected app happens to be packaged inside your namespace, that’s the one spot I’d watch closely, because it’s the gray area the notes don’t fully spell out.
What to do instead
If you’re injecting code via executeAnonymous, move to a real contract:
- Define a
globalinterface in your package, have the subscriber implement it, and invoke it through a versioned packaged entry point usingType.forName(). This is the path Salesforce explicitly recommends. - For external integrations, ask the subscriber to expose the logic as an Apex REST resource (
@RestResource) and call that endpoint directly. You get a stable signature instead of a string of Apex you hope compiles. - Or wrap the logic in an Invocable Action and call it through the Actions REST API.
And even if your particular flow squeaks past this one update, executeAnonymous is clearly on Salesforce’s list. Every release tightens it a little more. Build the proper interface now, on your schedule, instead of scrambling when the next clamp shows up.