Back to blog

JEP-200: Remoting / XStream whitelist integrated into Jenkins core

Jesse Glick
January 13, 2018

There is a newer version of the announcement for Jenkins administrators. Please see this blogpost.

Overview

JEP-200 has been integrated into Jenkins weekly builds and (if all goes well) will be a part of the next LTS line. In a nutshell, this change is a security hardening measure to be less permissive about deserializing Java classes defined in the Java Platform or libraries bundled with Jenkins. For several years now, Jenkins has specifically blacklisted certain classes and packages according to known or suspected exploits; now it will reject all classes not explicitly mentioned in a whitelist, or defined in Jenkins core or plugins.

For Jenkins administrators

Before upgrade

Back up your Jenkins instance prior to upgrade so you have any easy way of rolling back. If you are running any of the plugins listed in Plugins affected by fix for JEP-200, update them after taking the backup but before upgrading Jenkins core.

If you have a way of testing the upgrade in an isolated environment before applying it to production, do so now.

Using backups and a staging server is good advice before any upgrade but especially this one, with a relatively high risk of regression.

After upgrade

To the extent that advance testing of the impact of this change on popular plugins has been completed, most users (and even plugin developers) should not notice any difference. If you do encounter a java.lang.SecurityException: Rejected: some.pkg.and.ClassName in the Jenkins UI or logs, you may have found a case where an unusual plugin, or an unusual usage mode of a common plugin, violates the existing whitelist. This will be visible in the Jenkins system log as a message from jenkins.security.ClassFilterImpl like the following:

some.pkg.and.ClassName in file:/var/lib/jenkins/plugins/some-plugin-name/WEB-INF/lib/some-library-1.2.jar might be dangerous, so rejecting; see https://jenkins.io/redirect/class-filter/

where the link would direct you here.

If you find such a case, please report it in the Jenkins issue tracker, under the appropriate plugin component. Link it to JENKINS-47736 and add the JEP-200 label. If at all possible, include complete steps to reproduce the problem from scratch. Jenkins developers will strive to evaluate the reason for the violation and offer a fix in the form of a core and/or plugin update. For more details and current status, see Plugins affected by fix for JEP-200.

Assuming you see no particular reason to think that the class in question has dangerous deserialization semantics, which is rare, it is possible to work around the problem in your own installation as a temporary expedient. Simply make note of any class name(s) mentioned in such log messages, and run Jenkins with this startup option (details will depend on your installation method):

-Dhudson.remoting.ClassFilter=some.pkg.and.ClassName,some.pkg.and.OtherClassName

For plugin developers

Testing plugins against Jenkins 2.102 and above

As a plugin developer encountering this kind of error, your first task is to ensure that it is reproducible in a functional (JenkinsRule) test when running Jenkins 2.102 or newer to reproduce the error.

mvn test -Djenkins.version=2.102 -Denforcer.skip=true

The above assumes you are using a recent 2.x or 3.x parent Plugin POM. For certain cases you may need to use Plugin Compat Tester (PCT) to run tests against Jenkins core versions newer than your baseline.

Running PCT against the latest Jenkins core:

java -jar pct-cli.jar -reportFile $(pwd)/out/pct-report.xml \
    -workDirectory $(pwd)/work -skipTestCache true -mvn $(which mvn) \
    -includePlugins ${ARTIFACT_ID} -localCheckoutDir ${YOUR_PLUGIN_REPO}

You may need to run tests using an agent or force saves of plugin settings.

For maven plugins you can also specify custom Jenkins versions in Jenkinsfile to run tests against JEP-200:

buildPlugin(jenkinsVersions: [null, '2.102'])

(again picking whatever version you need to test against) so that the test is included during CI builds, even while your minimum core baseline predates JEP-200.

If your plugins are built with Gradle, your mileage may vary.

Making plugins compatible with Jenkins 2.102 or above

If you discover a compatibility issue in your plugin, you then have several choices for fixing the problem:

  • Ideally, simplify your code so that the mentioned class is not deserialized via Jenkins Remoting or XStream to begin with:

    • If the problem occurred when receiving a response from an agent, change your Callable (or FileCallable) to return a plainer type.

    • If the problem occurred when saving an XML file (such as a config.xml or build.xml), use a plainer type in non-transient fields in your persistable plugin classes.

  • If the class(es) are defined in the Java Platform or some library bundled in Jenkins core, propose a pull request adding it to core/src/main/resources/jenkins/security/whitelisted-classes.txt in jenkinsci/jenkins.

  • If the class(es) are defined in a third-party library bundled in your plugin, create a resource file META-INF/hudson.remoting.ClassFilter listing them. (example)

    • You may also do this for Java or Jenkins core library classes, as a hotfix until your core baseline includes the whitelist entry proposed above.

  • If the class(es) are defined in a JAR you build and then bundle in your plugin’s *.jpi, add a Jenkins-ClassFilter-Whitelisted: true manifest entry. This whitelists every class in the JAR. (example)

About the author

Jesse Glick

Jesse has been developing Jenkins core and plugins for years. He is the coauthor with Kohsuke of the core infrastructure of the Pipeline system.