{"record":{"id":"e517a2a3eae8aefd","repo":"chinabugotech/hutool","slug":"unauthorized-deserialization-attempt-by-black-list","errorCode":null,"errorMessage":"Unauthorized deserialization attempt by black list","messagePattern":"Unauthorized deserialization attempt by black list","errorType":"exception","errorClass":"InvalidClassException","httpStatus":null,"severity":"critical","filePath":"hutool-core/src/main/java/cn/hutool/core/io/ValidateObjectInputStream.java","lineNumber":84,"sourceCode":"\t/**\n\t * 只允许反序列化SerialObject class\n\t */\n\t@Override\n\tprotected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {\n\t\tvalidateClassName(desc.getName());\n\t\treturn super.resolveClass(desc);\n\t}\n\n\t/**\n\t * 验证反序列化的类是否合法\n\t * @param className 类名\n\t * @throws InvalidClassException 非法类\n\t */\n\tprivate void validateClassName(String className) throws InvalidClassException {\n\t\t// 黑名单\n\t\tif(CollUtil.isNotEmpty(this.blackClassSet)){\n\t\t\tif(this.blackClassSet.contains(className)){\n\t\t\t\tthrow new InvalidClassException(\"Unauthorized deserialization attempt by black list\", className);\n\t\t\t}\n\t\t}\n\n\t\tif(CollUtil.isEmpty(this.whiteClassSet) || this.whiteClassSet.contains(className)){\n\t\t\treturn;\n\t\t}\n\n\t\tthrow new InvalidClassException(\"Unauthorized deserialization attempt\", className);\n\t}\n}\n","sourceCodeStart":66,"sourceCodeEnd":95,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/io/ValidateObjectInputStream.java#L66-L95","documentation":"ValidateObjectInputStream overrides resolveClass to inspect each class during deserialization. If a class name is found in the black list (populated via refuse()), it throws InvalidClassException(\"Unauthorized deserialization attempt by black list\"). This blocks known dangerous gadget classes used in Java deserialization attacks.","triggerScenarios":"Deserializing an object stream whose class, or any referenced class, matches a name added to the black list via refuse().","commonSituations":"Receiving untrusted serialized data containing gadget classes (e.g. CommonsCollectionsInvoker); a class needed at runtime was accidentally added to the black list; a library upgrade introduced a class now present in a shared black list.","solutions":["If the class is legitimately expected, remove it from the black list (stop calling refuse() with it).","If the data is untrusted, this throw is correct protection — catch InvalidClassException and reject/audit the input.","Switch to an explicit white list via accept() for tighter, intent-based control."],"exampleFix":"// before: needed class accidentally refused\nvois.refuse(MyDto.class);\nMyDto o = (MyDto) IoUtil.readObj(vois, MyDto.class); // InvalidClassException\n\n// after: only refuse real gadget classes\nvois.refise(com.example.dangerous.Gadget.class);\nvois.accept(MyDto.class);\nMyDto o = (MyDto) IoUtil.readObj(vois, MyDto.class);","handlingStrategy":"try-catch","validationCode":"// Only refuse classes you never want to deserialize.\nvois.refuse(org.apache.commons.collections.functors.InvokerTransformer.class);\nvois.refise(MyDto.class); // <- remove this if MyDto is legitimate\n","typeGuard":null,"tryCatchPattern":"try {\n    return IoUtil.readObj(vois, clazz);\n} catch (java.io.InvalidClassException e) {\n    if (e.getMessage().contains(\"black list\")) {\n        // blocked by blacklist: audit/reject the untrusted payload\n        throw new SecurityException(\"rejected blacklisted class: \" + e.classname, e);\n    }\n    throw e;\n}","preventionTips":["Keep the black list limited to real gadget classes; do not refuse types you need.","Prefer a white list (accept()) for intent-based control over deserialization.","Never deserialize untrusted streams without validation; treat black-list hits as attacks."],"tags":["security","deserialization","blacklist"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}