frohoff/ysoserial · warning · IOException

Not allowed to read object

Error message

Not allowed to read object

What it means

JRMPListener installs a strict ObjectInputStream whose resolveClass only permits a small whitelist (ObjID[], ObjID, UID) so unmarshalling attacker-controlled data cannot instantiate arbitrary classes. Any other class name in the stream causes IOException("Not allowed to read object"). This is a deliberate deserialization-gadget defense, not a bug.

Solutions

  1. Confirm the client only sends the minimal JRMP handshake objects (ObjID, UID, primitive fields)
  2. If you control the payload, strip extra serialized objects from the stream
  3. If a new required type is legitimate, extend the whitelist in resolveClass deliberately (understand the deserialization risk)
  4. Do not whitelist arbitrary classes — that reintroduces the gadget vulnerability

Example fix

// before
} else if ( "java.rmi.server.UID".equals(desc.getName())) {
    return UID.class;
}
throw new IOException("Not allowed to read object");
// after
} else if ( "java.rmi.server.UID".equals(desc.getName())) {
    return UID.class;
} else if ( "java.lang.String".equals(desc.getName())) { // only if genuinely needed
    return String.class;
}
throw new IOException("Not allowed to read object");
Defensive patterns

Strategy: validation

Validate before calling

// client side: ensure the stream only contains whitelisted types
// allowed: ObjID, UID, primitive fields; strip any other Serializable objects first

Type guard

static boolean isWhitelisted(Class<?> c) {
    return c == ObjID.class || c == ObjID[].class || c == UID.class;
}

Try / catch

try {
    sendHandshake(stream);
} catch (IOException e) {
    if (e.getMessage().equals("Not allowed to read object")) {
        // remove non-whitelisted objects from the outgoing stream
    }
}

Prevention

When it happens

Trigger: During doCall/doMessage, the ObjectInputStream encounters a class descriptor whose name is not exactly one of 'java.rmi.server.ObjID[]', 'java.rmi.server.ObjID', or 'java.rmi.server.UID' — e.g. a client sends a serialized object graph with extra classes.

Common situations: A real RMI client (or exploit payload) sends serialized objects beyond the minimal handshake the listener expects; a client's stream includes string or other object types the whitelist does not cover.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of frohoff/ysoserial@218bcffcaa (2026-09-12). Data as JSON: /api/errors/37c4c76122a41915. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/ysoserial/exploit/JRMPListener.java:256

        }

        s.close();
    }


    private void doCall ( DataInputStream in, DataOutputStream out, Object payload ) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(in) {

            @Override
            protected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
                if ( "[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
                    return ObjID[].class;
                } else if ("java.rmi.server.ObjID".equals(desc.getName())) {
                    return ObjID.class;
                } else if ( "java.rmi.server.UID".equals(desc.getName())) {
                    return UID.class;
                }
                throw new IOException("Not allowed to read object");
            }
        };

        ObjID read;
        try {
            read = ObjID.read(ois);
        }
        catch ( java.io.IOException e ) {
            throw new MarshalException("unable to read objID", e);
        }


        if ( read.hashCode() == 2 ) {
            ois.readInt(); // method
            ois.readLong(); // hash
            System.err.println("Is DGC call for " + Arrays.toString((ObjID[])ois.readObject()));
        }

View on GitHub (pinned to 218bcffcaa)