{"schema_version": "1.6.1", "id": "CVE-2026-47065", "summary": "Critical Deserialization Allow-list Bypass via resolveProxyClass - ZDRES-232", "details": "ZDRES-232: resolveProxyClass Not Overridden - acceptMatchers Filter Bypass via java.lang.reflect.Proxy\n\n\nAssessment: Fully addressed.\n\n\nWhen the serialised stream contains a TC_PROXYCLASSDESC (the marker \nfor a java.lang.reflect.Proxy ), JDK’s ObjectInputStream.readProxyDesc()\n is\ndispatched. JDK then calls the default \nObjectInputStream.resolveProxyClass(interfaces) implementation, which \nperforms Class.forName(intf, false, latestUserDefinedLoader()) for EACH \ninterface name and constructs the proxy class â€” bypassing the accepted\n classes list .\n\n\nZDRES-233: Class.forName(name, initialize=true, classLoader) in \nreadClassDescriptor Triggers Static Initialiser of Allow-Listed Classes\n\n\nAssessment: Fully addressed.\n\n\nFor ANY class on the allow-list, deserialising a stream that names it triggers the class’s \n (static initialiser) BEFORE any instance is constructed. This means an \nattacker who supplies a class name on the allow-list (e.g., the \ndeveloper wrote accept(“com.myapp.*\") , attacker supplies \ncom.myapp.SomeClass ) causes <clinit> of SomeClass â€” and many \nreal-world classes have side-effecting static initialisers\n\n\nBoth issues have been fixed.", "affected": [{"ranges": [{"type": "SEMVER", "events": [{"introduced": "2.2.0"}, {"fixed": "2.2.8"}]}, {"type": "SEMVER", "events": [{"introduced": "2.1.0"}, {"fixed": "2.1.13"}]}, {"type": "SEMVER", "events": [{"introduced": "2.0.0"}, {"fixed": "2.0.29"}]}]}], "references": [{"type": "WEB", "url": "https://lists.apache.org/thread/y7xj1bl8qo47p9bktb11hg5v6k1d4dyj"}]}