Adds a guard to disable ObjectInputStream.readObject
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Paranoid Java Serialization

LEGAL WARNING: This project modifies the boot classpath, which is fine locally, but cannot be deployed as it contravenes section F of the Oracle Binary Code License Agreement. If you see the java executable Non-Standard Options, there is a note saying "Do not deploy applications that use this option to override a class in rt.jar because this violates the Java Runtime Environment binary code license."

Please consider using an agent-based solution like NotSoSerial instead.


This is a proof of concept that hacks to provide JVM level control over Java object serialization. Other solutions are user level -- they will work individually, but they don't change the behavior of internal libraries or application servers. This will enforce behavior at the lowest level.

See the blog post and the original talk for details.


mvn package


Create a file in your local application directory:


And copy the paranoid-java-serialization-1.0-SNAPSHOT.jar created from the package to your local application.

Then run Java with:

java \
   -Xbootclasspath/p:paranoid-java-serialization-1.0-SNAPSHOT.jar \


Because this is a hack of ObjectInputStream, it's harder to see what's changed between this and the stock version.

First, you can disable serialization entirely:

public final Object readObject()
            throws IOException, ClassNotFoundException
    String enabled ="paranoid.serialization.enabled");
    if (! Boolean.parseBoolean(enabled)) {
        throw new InvalidClassException("Object deserialization is disabled!");


Second: you can whitelist and blacklist based on class name:

/** Set of blacklisted class name patterns. */
private static final java.util.Set<Pattern> blacklistPatterns;

/** Set of whitelisted class name patterns. */
private static final java.util.Set<Pattern> whitelistPatterns;

// JUL isn't ideal, but it's the out of the box one.
private static final Logger logger = Logger.getLogger("");

static {

    final String blacklist = Security.getProperty("paranoid.serialization.blacklist");
    blacklistPatterns = parsePatterns(blacklist);

    final String whitelist = Security.getProperty("paranoid.serialization.whitelist");
    whitelistPatterns = parsePatterns(whitelist);

private static Set<Pattern> parsePatterns(String listString) {
    final Set<Pattern> listSet = new HashSet<>();
    if (listString != null) {
        final String[] regexArray = listString.split(",\\s*");
        for (String regex : regexArray) {
            Pattern whitePattern = Pattern.compile(regex);
    return java.util.Collections.unmodifiableSet(listSet);


protected Class<?> resolveClass(ObjectStreamClass desc)
            throws IOException, ClassNotFoundException
    String name = desc.getName();
    logger.fine("resolveClass: resolving " + name);

    // From by

    //Enforce blacklist
    for (Pattern blackPattern : blacklistPatterns) {
        Matcher blackMatcher = blackPattern.matcher(name);
        if (blackMatcher.find()) {
            logger.warning("resolveClass: rejecting blacklisted class " + name);
            String msg = "[!] Blocked by blacklist '"
                    + blackPattern.pattern() + "'. Match found for '" + name + "'";
            throw new InvalidClassException(msg);

    //Enforce whitelist if it exists.
    if (! whitelistPatterns.isEmpty()) {
        boolean safeClass = false;
        for (Pattern whitePattern: whitelistPatterns) {
            Matcher whiteMatcher = whitePattern.matcher(name);
            if (whiteMatcher.find()) {
                safeClass = true;

        if (!safeClass) {
            logger.warning("resolveClass: rejecting class " + name + " not found in whitelist.");
            String msg = "[!] Blocked by whitelist. No match found for '" + name + "'";
            throw new InvalidClassException(msg);

    try {
        logger.fine("resolveClass: accepting class " + name);
        return Class.forName(name, false, latestUserDefinedLoader());
    } catch (ClassNotFoundException ex) {
        Class<?> cl = primClasses.get(name);
        if (cl != null) {
            return cl;
        } else {
            throw ex;


If you are whitelisting, it can be helpful to run through the application first with a log of all the existing classes.

While you can use configure java.util.logging through a properties file, it's probably better to use SLF4J and the JUL to SLF4J bridge, after which you can use Logback. You will need to add the following as initialization:



Because this is a modification of OpenJDK code, the GPL v2 license applies to all of this code as well.

Also, because this is a modification of Oracle code, I will not be providing a binary distribution and uploading it to Maven unless I have their express permission. Sorry about that.

 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit if you need additional information or have any
 * questions.