{"record":{"id":"ba4c33c4c6e32691","repo":"spring-projects/spring-security","slug":"the-class-with-id-and-name-of-classname-is-not","errorCode":null,"errorMessage":"The class with {id} and name of {className} is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See https://github.com/spring-projects/spring-security/issues/4370 for details","messagePattern":"The class with (.+?) and name of (.+?) is not in the allowlist\\. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin\\. If the serialization is only done by a trusted source, you can also enable default typing\\. See https://github\\.com/spring-projects/spring-security/issues/4370 for details","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/springframework/security/jackson2/SecurityJackson2Modules.java","lineNumber":299,"sourceCode":"\n\t\t@Override\n\t\tpublic JavaType typeFromId(DatabindContext context, String id) throws IOException {\n\t\t\tDeserializationConfig config = (DeserializationConfig) context.getConfig();\n\t\t\tJavaType result = this.delegate.typeFromId(context, id);\n\t\t\tString className = result.getRawClass().getName();\n\t\t\tif (isInAllowlist(className)) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tboolean isExplicitMixin = config.findMixInClassFor(result.getRawClass()) != null;\n\t\t\tif (isExplicitMixin) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tJacksonAnnotation jacksonAnnotation = AnnotationUtils.findAnnotation(result.getRawClass(),\n\t\t\t\t\tJacksonAnnotation.class);\n\t\t\tif (jacksonAnnotation != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"The class with \" + id + \" and name of \" + className\n\t\t\t\t\t+ \" is not in the allowlist. \"\n\t\t\t\t\t+ \"If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. \"\n\t\t\t\t\t+ \"If the serialization is only done by a trusted source, you can also enable default typing. \"\n\t\t\t\t\t+ \"See https://github.com/spring-projects/spring-security/issues/4370 for details\");\n\t\t}\n\n\t\tprivate boolean isInAllowlist(String id) {\n\t\t\treturn ALLOWLIST_CLASS_NAMES.contains(id);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDescForKnownTypeIds() {\n\t\t\treturn this.delegate.getDescForKnownTypeIds();\n\t\t}\n\n\t\t@Override\n\t\tpublic JsonTypeInfo.Id getMechanism() {\n\t\t\treturn this.delegate.getMechanism();","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/core/src/main/java/org/springframework/security/jackson2/SecurityJackson2Modules.java#L281-L317","documentation":"SecurityJackson2Modules validates polymorphic deserialization targets against an allowlist of registered Spring Security classes before instantiating them. When Jackson's default typing resolves a type id to a class that was not explicitly enabled via SecurityJackson2Modules.enableDefaultTyping or a mixin, typeFromId rejects it with this IllegalArgumentException. This is a deliberate deserialization-safety guard introduced after spring-security#4370 to prevent gadget-class attacks through untrusted JSON.","triggerScenarios":"Calling ObjectMapper.readValue (or the ObjectMapper from SecurityJackson2Modules) on JSON containing @class / type id fields naming classes not covered by the allowlist; deserializing payloads serialized with custom UserDetails/Auth implementations without registering their mixins; enabling default typing manually instead of via SecurityJackson2Modules.enableDefaultTyping.","commonSituations":"Spring Session / Spring Security OAuth cache deserialization after upgrading Spring Security and adding new class fields; round-tripping custom Authentication or UserDetails objects through Redis or HTTP session JSON; copying an ObjectMapper from another service that allowlists different classes.","solutions":["Register the class's mixin with SecurityJackson2Modules (mapper.registerMixins or SecurityJackson2Modules mixins map) so its type id resolves explicitly","Use SecurityJackson2Modules.enableDefaultTyping(mapper, DefaultTyping.NON_FINAL, As.PROPERTY) on the ObjectMapper rather than generic activateDefaultTyping","Prefer deserializing into known Spring Security types; for custom types, subclass and add a Jackson mixin declaring @JsonTypeInfo and @JsonDeserialize","If payloads are only produced by trusted code, explicitly opt into default typing as the message suggests, and document the trust boundary"],"exampleFix":"// before\nObjectMapper mapper = new ObjectMapper();\nmapper.activateDefaultTyping(...); // class not allowlisted -> IllegalArgumentException\n// after\nObjectMapper mapper = new ObjectMapper();\nSecurityJackson2Modules.enableDefaultTyping(mapper);\nmapper.registerMixins(MyCustomToken.class, MyCustomTokenMixin.class);","handlingStrategy":"validation","validationCode":"Class<?> raw = null;\ntry { raw = mapper.getTypeFactory().findClass(typeId); } catch (ClassNotFoundException e) { /* reject */ }\nboolean allowlisted = raw != null && (SecurityJackson2Modules.isWellKnownReturnValueType(raw)\n    || registeredMixins.containsKey(raw));\nif (!allowlisted) { throw new IllegalArgumentException(\"Type not allowlisted: \" + typeId); }","typeGuard":"static boolean isAllowlisted(Class<?> clazz) {\n    return clazz != null && AnnotationUtils.findAnnotation(clazz, JacksonAnnotation.class) != null;\n}","tryCatchPattern":"try {\n    return mapper.readValue(json, Object.class);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"is not in the allowlist\")) {\n        // log and reject payload; register missing mixin if legitimate\n    }\n    throw e;\n}","preventionTips":["Always build deserializing ObjectMappers via SecurityJackson2Modules.enableDefaultTyping, never raw activateDefaultTyping","Register a mixin for every custom UserDetails/Authentication class you serialize","Test round-trip serialization/deserialization of all cached security objects in CI","Never deserialize security JSON from untrusted sources; prefer binary/session storage for trusted contexts"],"tags":["jackson","deserialization","security","allowlist"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}