Overview
About vulnerability
SVG ImageDescription
Spring Statemachine’s Kryo-based persistence backends (JPA, MongoDB, Redis and ZooKeeper) deserialise persisted state-machine contexts without enforcing a class allowlist (CWE-502, deserialisation of untrusted data), which can lead to remote code execution inside the application JVM.
SVG ImageAffected Spring Products and Versions
Spring Statemachine:
- 4.0.0 - 4.0.1
- 3.2.0 - 3.2.4
SVG ImageMitigation
Users of affected versions should upgrade to the corresponding fixed version:
| Affected version(s) | Fix version | Availability |
|---|---|---|
| 4.0.x | 4.0.2 | OSS |
| 4.0.x | 4.0.1.1 | Enterprise Support Only |
| 3.2.x | 3.2.5 | Enterprise Support Only |
The fixed releases enable Kryo.setRegistrationRequired(true) and register an explicit allowlist of framework and JDK types via a new KryoStateMachineSerialisationDefaults helper. This is a behaviour change that affects every application using custom state or event types: those types must now be registered with Kryo explicitly, otherwise Kryo throws IllegalArgumentException: Class is not registered on the first persist / load.
SVG ImageRegister application-specific state and event types
Each persistence-layer factory accepts a new Consumer<Kryo> callback that is invoked once per Kryo instance after the framework defaults are applied. Use it to register your application’s S (state) and E (event) classes.
SVG ImageJPA:
@Bean public StateMachineRuntimePersister<MyStates, MyEvents, String> stateMachineRuntimePersister(JpaStateMachineRepository repo) { return new JpaPersistingStateMachineInterceptor<>(repo, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); }); }
SVG ImageMongoDB:
@Bean public StateMachineRuntimePersister<MyStates, MyEvents, String> stateMachineRuntimePersister(MongoDbStateMachineRepository repo) { return new MongoDbPersistingStateMachineInterceptor<>(repo, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); }); }
SVG ImageRedis:
@Bean public StateMachineRuntimePersister<MyStates, MyEvents, String> stateMachineRuntimePersister(RedisStateMachineRepository repo) { return new RedisPersistingStateMachineInterceptor<>(repo, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); }); }
SVG ImageZooKeeper:
ZookeeperStateMachineEnsemble<MyStates, MyEvents> ensemble = new ZookeeperStateMachineEnsemble<>(curatorClient, “/state”, true, 32, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); });
If event headers or extended-state variables contain types beyond the JDK and framework defaults already registered by KryoStateMachineSerialisationDefaults, register those types inside the same Consumer<Kryo> as well.
SVG ImageWire-format incompatibility
With registration required, Kryo identifies classes by registered numeric id rather than by class name. State-machine contexts persisted by older releases cannot be read by the fixed version. Drain or migrate the persistence backend during the upgrade, or accept that pre-upgrade contexts are unreadable.
SVG ImageRedis key namespace
RedisStateMachineContextRepository now prepends every Redis key with a fixed namespace (ssm:context: by default) so that user-supplied machine ids cannot collide with unrelated keys in the same logical database. Existing keys written by older releases are not visible after the upgrade; either rewrite contexts under the new namespace or, only if backwards compatibility is required, pass an empty prefix:
new RedisStateMachineContextRepository<>(connectionFactory, “”, kryo -> kryo.register(MyStates.class));
SVG ImageCredit
This issue was discovered internally.
SVG ImageReferences
SVG ImageHistory
- 2026-06-11: Initial vulnerability report published.
Details
SVG ImageDescription
Spring Statemachine’s Kryo-based persistence backends (JPA, MongoDB, Redis and ZooKeeper) deserialise persisted state-machine contexts without enforcing a class allowlist (CWE-502, deserialisation of untrusted data), which can lead to remote code execution inside the application JVM.
SVG ImageAffected Spring Products and Versions
Spring Statemachine:
- 4.0.0 - 4.0.1
- 3.2.0 - 3.2.4
SVG ImageMitigation
Users of affected versions should upgrade to the corresponding fixed version:
| Affected version(s) | Fix version | Availability |
|---|---|---|
| 4.0.x | 4.0.2 | OSS |
| 4.0.x | 4.0.1.1 | Enterprise Support Only |
| 3.2.x | 3.2.5 | Enterprise Support Only |
The fixed releases enable Kryo.setRegistrationRequired(true) and register an explicit allowlist of framework and JDK types via a new KryoStateMachineSerialisationDefaults helper. This is a behaviour change that affects every application using custom state or event types: those types must now be registered with Kryo explicitly, otherwise Kryo throws IllegalArgumentException: Class is not registered on the first persist / load.
SVG ImageRegister application-specific state and event types
Each persistence-layer factory accepts a new Consumer<Kryo> callback that is invoked once per Kryo instance after the framework defaults are applied. Use it to register your application’s S (state) and E (event) classes.
SVG ImageJPA:
@Bean public StateMachineRuntimePersister<MyStates, MyEvents, String> stateMachineRuntimePersister(JpaStateMachineRepository repo) { return new JpaPersistingStateMachineInterceptor<>(repo, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); }); }
SVG ImageMongoDB:
@Bean public StateMachineRuntimePersister<MyStates, MyEvents, String> stateMachineRuntimePersister(MongoDbStateMachineRepository repo) { return new MongoDbPersistingStateMachineInterceptor<>(repo, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); }); }
SVG ImageRedis:
@Bean public StateMachineRuntimePersister<MyStates, MyEvents, String> stateMachineRuntimePersister(RedisStateMachineRepository repo) { return new RedisPersistingStateMachineInterceptor<>(repo, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); }); }
SVG ImageZooKeeper:
ZookeeperStateMachineEnsemble<MyStates, MyEvents> ensemble = new ZookeeperStateMachineEnsemble<>(curatorClient, “/state”, true, 32, kryo -> { kryo.register(MyStates.class); kryo.register(MyEvents.class); });
If event headers or extended-state variables contain types beyond the JDK and framework defaults already registered by KryoStateMachineSerialisationDefaults, register those types inside the same Consumer<Kryo> as well.
SVG ImageWire-format incompatibility
With registration required, Kryo identifies classes by registered numeric id rather than by class name. State-machine contexts persisted by older releases cannot be read by the fixed version. Drain or migrate the persistence backend during the upgrade, or accept that pre-upgrade contexts are unreadable.
SVG ImageRedis key namespace
RedisStateMachineContextRepository now prepends every Redis key with a fixed namespace (ssm:context: by default) so that user-supplied machine ids cannot collide with unrelated keys in the same logical database. Existing keys written by older releases are not visible after the upgrade; either rewrite contexts under the new namespace or, only if backwards compatibility is required, pass an empty prefix:
new RedisStateMachineContextRepository<>(connectionFactory, “”, kryo -> kryo.register(MyStates.class));
SVG ImageCredit
This issue was discovered internally.
SVG ImageReferences
SVG ImageHistory
- 2026-06-11: Initial vulnerability report published.