VYPR
High severity8.8NVD Advisory· Published Apr 7, 2016· Updated May 6, 2026

CVE-2016-0792

CVE-2016-0792

Description

Multiple unspecified API endpoints in Jenkins before 1.650 and LTS before 1.642.2 allow remote authenticated users to execute arbitrary code via serialized data in an XML file, related to XStream and groovy.util.Expando.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.jenkins-ci.main:jenkins-coreMaven
>= 1.643, < 1.6501.650
org.jenkins-ci.main:jenkins-coreMaven
< 1.642.21.642.2

Affected products

3
  • Jenkins/Jenkins2 versions
    cpe:2.3:a:jenkins:jenkins:*:*:*:*:*:*:*:*+ 1 more
    • cpe:2.3:a:jenkins:jenkins:*:*:*:*:*:*:*:*range: <=1.649
    • cpe:2.3:a:jenkins:jenkins:*:*:*:*:lts:*:*:*range: <=1.642.1
  • cpe:2.3:a:redhat:openshift:3.1:*:*:*:enterprise:*:*:*

Patches

1
7f202f0317e6

Merge pull request #60 from jenkinsci-cert/SECURITY-247-v2

https://github.com/jenkinsci/jenkinsJesse GlickFeb 11, 2016via ghsa
3 files changed · +176 0
  • core/src/main/java/hudson/util/XStream2.java+29 0 modified
    @@ -47,6 +47,7 @@
     import hudson.PluginManager;
     import hudson.PluginWrapper;
     import hudson.diagnosis.OldDataMonitor;
    +import hudson.remoting.ClassFilter;
     import hudson.util.xstream.ImmutableSetConverter;
     import hudson.util.xstream.ImmutableSortedSetConverter;
     import jenkins.model.Jenkins;
    @@ -159,6 +160,8 @@ private void init() {
             // but before reflection-based one kicks in.
             registerConverter(new AssociatedConverterImpl(this), -10);
     
    +        registerConverter(new BlacklistedTypesConverter(), PRIORITY_VERY_HIGH); // SECURITY-247 defense
    +
             registerConverter(new DynamicProxyConverter(getMapper()) { // SECURITY-105 defense
                 @Override public boolean canConvert(Class type) {
                     return /* this precedes NullConverter */ type != null && super.canConvert(type);
    @@ -434,4 +437,30 @@ class PluginClassOwnership implements ClassOwnership {
     
         }
     
    +    private static class BlacklistedTypesConverter implements Converter {
    +        @Override
    +        public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
    +            throw new UnsupportedOperationException("Refusing to marshal for security reasons");
    +        }
    +
    +        @Override
    +        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    +            throw new ConversionException("Refusing to unmarshal for security reasons");
    +        }
    +
    +        @Override
    +        public boolean canConvert(Class type) {
    +            if (type == null) {
    +                return false;
    +            }
    +            try {
    +                ClassFilter.DEFAULT.check(type);
    +                ClassFilter.DEFAULT.check(type.getName());
    +            } catch (SecurityException se) {
    +                // claim we can convert all the scary stuff so we can throw exceptions when attempting to do so
    +                return true;
    +            }
    +            return false;
    +        }
    +    }
     }
    
  • test/src/test/java/hudson/util/XStream2Security247Test.java+120 0 added
    @@ -0,0 +1,120 @@
    +package hudson.util;
    +
    +import hudson.model.Items;
    +import org.apache.commons.io.*;
    +import org.apache.commons.io.IOUtils;
    +import org.junit.Before;
    +import org.junit.Rule;
    +import org.junit.Test;
    +import org.junit.rules.TemporaryFolder;
    +import org.jvnet.hudson.test.Issue;
    +import org.jvnet.hudson.test.JenkinsRule;
    +import org.kohsuke.stapler.StaplerRequest;
    +import org.kohsuke.stapler.StaplerResponse;
    +import org.mockito.Mock;
    +import org.mockito.MockitoAnnotations;
    +
    +import javax.servlet.ServletInputStream;
    +import java.io.File;
    +import java.io.IOException;
    +import java.io.InputStream;
    +
    +import static org.junit.Assert.assertFalse;
    +import static org.mockito.Mockito.when;
    +
    +public class XStream2Security247Test {
    +
    +    @Rule
    +    public JenkinsRule j = new JenkinsRule();
    +
    +    @Rule
    +    public TemporaryFolder f = new TemporaryFolder();
    +
    +    @Mock
    +    private StaplerRequest req;
    +
    +    @Mock
    +    private StaplerResponse rsp;
    +
    +    @Before
    +    public void setUp() throws Exception {
    +        MockitoAnnotations.initMocks(this);
    +    }
    +
    +    @Test
    +    @Issue("SECURITY-247")
    +    public void testXmlLoad() throws Exception {
    +        File exploitFile = f.newFile();
    +        try {
    +            // be extra sure there's no file already
    +            if (exploitFile.exists() && !exploitFile.delete()) {
    +                throw new IllegalStateException("file exists and cannot be deleted");
    +            }
    +            File tempJobDir = new File(j.jenkins.getRootDir(), "security247");
    +
    +            String exploitXml = org.apache.commons.io.IOUtils.toString(
    +                    XStream2Security247Test.class.getResourceAsStream(
    +                            "/hudson/util/XStream2Security247Test/config.xml"), "UTF-8");
    +
    +            exploitXml = exploitXml.replace("@TOKEN@", exploitFile.getAbsolutePath());
    +
    +            FileUtils.write(new File(tempJobDir, "config.xml"), exploitXml);
    +
    +            try {
    +                Items.load(j.jenkins, tempJobDir);
    +            } catch (Exception e) {
    +                // ignore
    +            }
    +            assertFalse("no file should be created here", exploitFile.exists());
    +        } finally {
    +            exploitFile.delete();
    +        }
    +    }
    +
    +    @Test
    +    @Issue("SECURITY-247")
    +    public void testPostJobXml() throws Exception {
    +        File exploitFile = f.newFile();
    +        try {
    +            // be extra sure there's no file already
    +            if (exploitFile.exists() && !exploitFile.delete()) {
    +                throw new IllegalStateException("file exists and cannot be deleted");
    +            }
    +            File tempJobDir = new File(j.jenkins.getRootDir(), "security247");
    +
    +            String exploitXml = org.apache.commons.io.IOUtils.toString(
    +                    XStream2Security247Test.class.getResourceAsStream(
    +                            "/hudson/util/XStream2Security247Test/config.xml"), "UTF-8");
    +
    +            exploitXml = exploitXml.replace("@TOKEN@", exploitFile.getAbsolutePath());
    +
    +            when(req.getMethod()).thenReturn("POST");
    +            when(req.getInputStream()).thenReturn(new Stream(IOUtils.toInputStream(exploitXml)));
    +            when(req.getContentType()).thenReturn("application/xml");
    +            when(req.getParameter("name")).thenReturn("foo");
    +
    +            try {
    +                j.jenkins.doCreateItem(req, rsp);
    +            } catch (Exception e) {
    +                // don't care
    +            }
    +
    +            assertFalse("no file should be created here", exploitFile.exists());
    +        } finally {
    +            exploitFile.delete();
    +        }
    +    }
    +
    +    private static class Stream extends ServletInputStream {
    +        private final InputStream inner;
    +
    +        public Stream(final InputStream inner) {
    +            this.inner = inner;
    +        }
    +
    +        @Override
    +        public int read() throws IOException {
    +            return inner.read();
    +        }
    +    }
    +}
    
  • test/src/test/resources/hudson/util/XStream2Security247Test/config.xml+27 0 added
    @@ -0,0 +1,27 @@
    +<map>
    +    <entry>
    +        <groovy.util.Expando>
    +            <expandoProperties>
    +                <entry>
    +                    <string>hashCode</string>
    +                    <org.codehaus.groovy.runtime.MethodClosure>
    +                        <delegate class="groovy.util.Expando" reference="../../../.."/>
    +                        <owner class="java.lang.ProcessBuilder">
    +                            <command>
    +                                <string>touch</string>
    +                                <string>@TOKEN@</string>
    +                            </command>
    +                            <redirectErrorStream>false</redirectErrorStream>
    +                        </owner>
    +                        <resolveStrategy>0</resolveStrategy>
    +                        <directive>0</directive>
    +                        <parameterTypes/>
    +                        <maximumNumberOfParameters>0</maximumNumberOfParameters>
    +                        <method>start</method>
    +                    </org.codehaus.groovy.runtime.MethodClosure>
    +                </entry>
    +            </expandoProperties>
    +        </groovy.util.Expando>
    +        <int>1</int>
    +    </entry>
    +</map>
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

11

News mentions

0

No linked articles in our index yet.