Skip to content

fix: check the remote deployment allow list before deserializing constructor args - #3493

Merged
pjfanning merged 1 commit into
apache:mainfrom
pjfanning:remote-deploy-allowlist-ordering
Aug 31, 2026
Merged

fix: check the remote deployment allow list before deserializing constructor args#3493
pjfanning merged 1 commit into
apache:mainfrom
pjfanning:remote-deploy-allowlist-ordering

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Motivation

DaemonMsgCreateSerializer.fromBinary resolved the peer-named actor class and then deserialized every constructor argument — each with a peer-chosen serializer id and manifest — before RemoteSystemDaemon consulted the remote deployment allow list (RemoteDaemon.scala).

So for a class the allow list rejects, a peer still got arbitrary nested deserialization performed on its behalf, for a deployment refused moments later. That weakens the guarantee the allow list is credited with: the check exists to bound what a peer can cause this node to do, but the surface-bearing work happened before it.

(For the avoidance of doubt: class loading here is Class.forName(fqcn, false, loader)initialize = false — so static initializers do not run. The argument deserialization is the part worth moving.)

Modification

  • Extract RemoteDeploymentAllowList (INTERNAL API, in RemoteDaemon.scala beside the related exception): it owns the two existing config keys — pekko.remote.deployment.enable-allow-list and …allowed-actor-classes — and the getCanonicalName comparison.
  • RemoteSystemDaemon and DaemonMsgCreateSerializer both use it, so the two sites cannot drift on either the keys or the comparison.
  • The serializer checks the allow list immediately after resolving the actor class and before deserializing any argument, logging at error with LogMarker.Security and throwing the same NotAllowedClassRemoteDeploymentAttemptException the daemon raises. RemoteSystemDaemon keeps its check as defence in depth.

No new configuration. With the allow list off — the default — behaviour is unchanged.

Result

With the allow list enabled, a rejected class is refused before any peer-supplied constructor argument is deserialized. The deployment is still refused, with the same exception and the same security-marked log signal, wherever it is caught.

Tests

  • sbt "remote/testOnly …DaemonMsgCreateSerializerAllowListSpec …DaemonMsgCreateSerializerAllowListDisabledSpec" — new specs, including one that registers a counting serializer for the constructor argument and asserts the count stays at zero for a rejected class (the ordering this change is about), plus a disabled-allow-list spec pinning the default behaviour
  • sbt "remote/testOnly org.apache.pekko.remote.classic.RemoteDeploymentAllowListSpec …AllowJavaSerializationSpec …NoJavaSerializationSpec" — existing specs pass unchanged, including the end-to-end allow-list rejection
  • sbt "remote/mimaReportBinaryIssues" — no issues

References

Refs #3478

…tructor args

Motivation:
DaemonMsgCreateSerializer.fromBinary loaded the peer-named actor class and then
deserialized every constructor argument - with peer-chosen serializer ids and
manifests - before RemoteSystemDaemon consulted the remote deployment allow
list. For a class the allow list rejects, that deserialization is attack surface
taken on for a deployment that is refused moments later, which weakens the
guarantee the allow list is credited with.

Modification:
Extract RemoteDeploymentAllowList, holding the two existing config keys and the
class-name comparison, and use it from both RemoteSystemDaemon and
DaemonMsgCreateSerializer so the two cannot drift. The serializer now checks the
allow list immediately after resolving the actor class and before deserializing
any argument, logging at error with LogMarker.Security and the same exception
RemoteSystemDaemon raises.

Result:
With the allow list enabled, a rejected class is refused before any
peer-supplied argument is deserialized. No new configuration, and no change
when the allow list is off, which is the default.

Tests:
- sbt "remote/testOnly org.apache.pekko.remote.serialization.DaemonMsgCreateSerializerAllowListSpec org.apache.pekko.remote.serialization.DaemonMsgCreateSerializerAllowListDisabledSpec" - new, incl. a counting serializer asserting args are not deserialized for a rejected class
- sbt "remote/testOnly org.apache.pekko.remote.classic.RemoteDeploymentAllowListSpec org.apache.pekko.remote.serialization.DaemonMsgCreateSerializerAllowJavaSerializationSpec org.apache.pekko.remote.serialization.DaemonMsgCreateSerializerNoJavaSerializationSpec" - existing specs pass unchanged
- sbt "remote/mimaReportBinaryIssues" - no issues

References:
Refs apache#3478
@pjfanning
pjfanning merged commit 347264a into apache:main Aug 31, 2026
10 checks passed
@pjfanning
pjfanning deleted the remote-deploy-allowlist-ordering branch August 31, 2026 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants