Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreSpring 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.
Spring Statemachine:
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.
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.
@Bean
public StateMachineRuntimePersister<MyStates, MyEvents, String>
stateMachineRuntimePersister(JpaStateMachineRepository repo) {
return new JpaPersistingStateMachineInterceptor<>(repo, kryo -> {
kryo.register(MyStates.class);
kryo.register(MyEvents.class);
});
}
@Bean
public StateMachineRuntimePersister<MyStates, MyEvents, String>
stateMachineRuntimePersister(MongoDbStateMachineRepository repo) {
return new MongoDbPersistingStateMachineInterceptor<>(repo, kryo -> {
kryo.register(MyStates.class);
kryo.register(MyEvents.class);
});
}
@Bean
public StateMachineRuntimePersister<MyStates, MyEvents, String>
stateMachineRuntimePersister(RedisStateMachineRepository repo) {
return new RedisPersistingStateMachineInterceptor<>(repo, kryo -> {
kryo.register(MyStates.class);
kryo.register(MyEvents.class);
});
}
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.
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.
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));
This issue was discovered internally.
To report a security vulnerability for a project within the Spring portfolio, see the Security Policy