chinabugotech/hutool · critical · InvalidClassException

Unauthorized deserialization attempt

Error message

Unauthorized deserialization attempt

What it means

When a white list is configured via accept(), ValidateObjectInputStream permits only those class names during deserialization. Any class not in the white list — including referenced superclasses, array element types, and standard JDK helper classes — throws InvalidClassException("Unauthorized deserialization attempt").

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/io/ValidateObjectInputStream.java:92

	/**
	 * 验证反序列化的类是否合法
	 * @param className 类名
	 * @throws InvalidClassException 非法类
	 */
	private void validateClassName(String className) throws InvalidClassException {
		// 黑名单
		if(CollUtil.isNotEmpty(this.blackClassSet)){
			if(this.blackClassSet.contains(className)){
				throw new InvalidClassException("Unauthorized deserialization attempt by black list", className);
			}
		}

		if(CollUtil.isEmpty(this.whiteClassSet) || this.whiteClassSet.contains(className)){
			return;
		}

		throw new InvalidClassException("Unauthorized deserialization attempt", className);
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Add the missing class and all types it references to the white list via accept().
  2. If you do not want whitelist enforcement, simply do not call accept() — an empty/absent white list allows all classes.
  3. Audit the full object graph (inspect the serialized descriptor names) and register every class.

Example fix

// before: only the top type registered
vois.accept(MyDto.class);
MyDto o = (MyDto) IoUtil.readObj(vois, MyDto.class); // throws for nested Item

// after: register the whole graph
vois.accept(MyDto.class, Item.class, java.util.ArrayList.class);
MyDto o = (MyDto) IoUtil.readObj(vois, MyDto.class);
Defensive patterns

Strategy: try-catch

Validate before calling

// Register the full object graph, not just the top type.
vois.accept(MyDto.class, Item.class, java.util.ArrayList.class, "[Lcom.example.Item;");
// Or, to allow all classes, do not call accept() at all.

Try / catch

try {
    return IoUtil.readObj(vois, clazz);
} catch (java.io.InvalidClassException e) {
    // e.classname tells you which class is missing from the white list
    vois.accept(Class.forName(e.classname)); // only if trusted
}

Prevention

When it happens

Trigger: Deserializing an object whose class, or any class reachable in its graph (supertypes, field types, array types), is not present in the configured white list.

Common situations: White list too narrow: missing a referenced type, an array variant, a superclass, or JDK core classes; a new model class added but not registered; forgetting that nested objects pull in additional class names.

Understand the failure class

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/2202aeeba510f93e. Report an issue: GitHub.