msrb pushed to jenkins (f21). "Fix multiple CVEs: (..more)"

notifications at fedoraproject.org notifications at fedoraproject.org
Wed Apr 1 16:37:36 UTC 2015


>From e51239c00ee63ff7a373990cc962b2fd9063b7ab Mon Sep 17 00:00:00 2001
From: Michal Srb <msrb at redhat.com>
Date: Sun, 29 Mar 2015 17:09:59 +0200
Subject: Fix multiple CVEs:

    - Resolves: CVE-2015-1806
    - Resolves: CVE-2015-1807
    - Resolves: CVE-2015-1813
    - Resolves: CVE-2015-1812
    - Resolves: CVE-2015-1810
    - Resolves: CVE-2015-1808
    - Resolves: CVE-2015-1809
    - Resolves: CVE-2015-1814
    - Resolves: CVE-2015-1811

diff --git a/0001-SECURITY-162-Capture-the-root-directory-in-VirtualFi.patch b/0001-SECURITY-162-Capture-the-root-directory-in-VirtualFi.patch
new file mode 100644
index 0000000..48b44fe
--- /dev/null
+++ b/0001-SECURITY-162-Capture-the-root-directory-in-VirtualFi.patch
@@ -0,0 +1,218 @@
+From dc44f55e27f1d884d494a56534232e4f46182ea8 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Fri, 27 Mar 2015 10:32:03 +0100
+Subject: [PATCH 1/9] [SECURITY-162] Capture the root directory in
+ VirtualFile.forFile and reject attempts to escape it.
+
+---
+ core/src/main/java/jenkins/util/VirtualFile.java   | 56 ++++++++++++++++--
+ .../test/java/jenkins/util/VirtualFileTest.java    | 67 ++++++++++++++++++++++
+ 2 files changed, 118 insertions(+), 5 deletions(-)
+ create mode 100644 core/src/test/java/jenkins/util/VirtualFileTest.java
+
+diff --git a/core/src/main/java/jenkins/util/VirtualFile.java b/core/src/main/java/jenkins/util/VirtualFile.java
+index 3ccd3f0..93bd62f 100644
+--- a/core/src/main/java/jenkins/util/VirtualFile.java
++++ b/core/src/main/java/jenkins/util/VirtualFile.java
+@@ -31,14 +31,19 @@ import hudson.remoting.Channel;
+ import hudson.remoting.VirtualChannel;
+ import hudson.util.DirScanner;
+ import hudson.util.FileVisitor;
++
+ import java.io.File;
+ import java.io.FileInputStream;
++import java.io.FileNotFoundException;
+ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.Serializable;
+ import java.net.URI;
+ import java.util.ArrayList;
+ import java.util.List;
++import java.util.logging.Level;
++import java.util.logging.Logger;
++
+ import javax.annotation.Nonnull;
+ 
+ import jenkins.MasterToSlaveFileCallable;
+@@ -209,12 +214,14 @@ public abstract class VirtualFile implements Comparable<VirtualFile>, Serializab
+      * @return a wrapper
+      */
+     public static VirtualFile forFile(final File f) {
+-        return new FileVF(f);
++        return new FileVF(f, f);
+     }
+     private static final class FileVF extends VirtualFile {
+         private final File f;
+-        FileVF(File f) {
++        private final File root;
++        FileVF(File f, File root) {
+             this.f = f;
++            this.root = root;
+         }
+             @Override public String getName() {
+                 return f.getName();
+@@ -223,46 +230,85 @@ public abstract class VirtualFile implements Comparable<VirtualFile>, Serializab
+                 return f.toURI();
+             }
+             @Override public VirtualFile getParent() {
+-                return forFile(f.getParentFile());
++                return new FileVF(f.getParentFile(), root);
+             }
+             @Override public boolean isDirectory() throws IOException {
++                if (isIllegalSymlink()) {
++                    return false;
++                }
+                 return f.isDirectory();
+             }
+             @Override public boolean isFile() throws IOException {
++                if (isIllegalSymlink()) {
++                    return false;
++                }
+                 return f.isFile();
+             }
+             @Override public boolean exists() throws IOException {
++                if (isIllegalSymlink()) {
++                    return false;
++                }
+                 return f.exists();
+             }
+             @Override public VirtualFile[] list() throws IOException {
++                if (isIllegalSymlink()) {
++                    return new VirtualFile[0];
++                }
+                 File[] kids = f.listFiles();
+                 if (kids == null) {
+                     return new VirtualFile[0];
+                 }
+                 VirtualFile[] vfs = new VirtualFile[kids.length];
+                 for (int i = 0; i < kids.length; i++) {
+-                    vfs[i] = forFile(kids[i]);
++                    vfs[i] = new FileVF(kids[i], root);
+                 }
+                 return vfs;
+             }
+             @Override public String[] list(String glob) throws IOException {
++                if (isIllegalSymlink()) {
++                    return new String[0];
++                }
+                 return new Scanner(glob).invoke(f, null);
+             }
+             @Override public VirtualFile child(String name) {
+-                return forFile(new File(f, name));
++                return new FileVF(new File(f, name), root);
+             }
+             @Override public long length() throws IOException {
++                if (isIllegalSymlink()) {
++                    return 0;
++                }
+                 return f.length();
+             }
+             @Override public long lastModified() throws IOException {
++                if (isIllegalSymlink()) {
++                    return 0;
++                }
+                 return f.lastModified();
+             }
+             @Override public boolean canRead() throws IOException {
++                if (isIllegalSymlink()) {
++                    return false;
++                }
+                 return f.canRead();
+             }
+             @Override public InputStream open() throws IOException {
++                if (isIllegalSymlink()) {
++                    throw new FileNotFoundException(f.getPath());
++                }
+                 return new FileInputStream(f);
+             }
++        private boolean isIllegalSymlink() { // TODO JENKINS-26838
++            try {
++                String myPath = f.getCanonicalPath();
++                String rootPath = root.getCanonicalPath();
++                if (!myPath.equals(rootPath) && !myPath.startsWith(rootPath + File.separatorChar)) {
++                    return true;
++                }
++            } catch (IOException x) {
++                Logger.getLogger(VirtualFile.class.getName()).log(Level.FINE, "could not determine symlink status of " + f, x);
++            }
++            return false;
++        }
+     }
+ 
+     /**
+diff --git a/core/src/test/java/jenkins/util/VirtualFileTest.java b/core/src/test/java/jenkins/util/VirtualFileTest.java
+new file mode 100644
+index 0000000..816bd2a
+--- /dev/null
++++ b/core/src/test/java/jenkins/util/VirtualFileTest.java
+@@ -0,0 +1,67 @@
++/*
++ * The MIT License
++ *
++ * Copyright 2015 Jesse Glick.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++
++package jenkins.util;
++
++import hudson.Util;
++import hudson.model.TaskListener;
++import java.io.File;
++import java.io.FileNotFoundException;
++import org.apache.commons.io.FileUtils;
++import org.apache.commons.io.IOUtils;
++import org.junit.Test;
++import static org.junit.Assert.*;
++import org.junit.Rule;
++import org.junit.rules.TemporaryFolder;
++import org.jvnet.hudson.test.Issue;
++
++public class VirtualFileTest {
++
++    @Rule public TemporaryFolder tmp = new TemporaryFolder();
++
++    @Issue("SECURITY-162")
++    @Test public void outsideSymlinks() throws Exception {
++        File ws = tmp.newFolder("ws");
++        FileUtils.write(new File(ws, "safe"), "safe");
++        Util.createSymlink(ws, "safe", "supported", TaskListener.NULL);
++        File other = tmp.newFolder("other");
++        FileUtils.write(new File(other, "secret"), "s3cr3t");
++        Util.createSymlink(ws, "../other/secret", "hack", TaskListener.NULL);
++        VirtualFile root = VirtualFile.forFile(ws);
++        VirtualFile supported = root.child("supported");
++        assertTrue(supported.isFile());
++        assertTrue(supported.exists());
++        assertEquals("safe", IOUtils.toString(supported.open(), (String) null));
++        VirtualFile hack = root.child("hack");
++        assertFalse(hack.isFile());
++        assertFalse(hack.exists());
++        try {
++            hack.open();
++            fail();
++        } catch (FileNotFoundException x) {
++            // OK
++        }
++    }
++
++}
+-- 
+2.1.0
+
diff --git a/0002-SECURITY-163-Treat-BadPaddingException-as-an-unloada.patch b/0002-SECURITY-163-Treat-BadPaddingException-as-an-unloada.patch
new file mode 100644
index 0000000..6aa9667
--- /dev/null
+++ b/0002-SECURITY-163-Treat-BadPaddingException-as-an-unloada.patch
@@ -0,0 +1,123 @@
+From 18845111edd7fb735c19d8d35f5dfcb3d64d944b Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Fri, 27 Mar 2015 11:49:38 +0100
+Subject: [PATCH 2/9] [SECURITY-163] Treat BadPaddingException as an unloadable
+ key and continue.
+
+---
+ .../jenkins/security/DefaultConfidentialStore.java |  9 +++
+ .../java/hudson/model/DownloadService2Test.java    | 65 ++++++++++++++++++++++
+ 2 files changed, 74 insertions(+)
+ create mode 100644 test/src/test/java/hudson/model/DownloadService2Test.java
+
+diff --git a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java
+index 88eb84f..8f70e9b 100644
+--- a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java
++++ b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java
+@@ -6,16 +6,19 @@ import hudson.util.Secret;
+ import hudson.util.TextFile;
+ import jenkins.model.Jenkins;
+ 
++import javax.crypto.BadPaddingException;
+ import javax.crypto.Cipher;
+ import javax.crypto.CipherInputStream;
+ import javax.crypto.CipherOutputStream;
+ import javax.crypto.SecretKey;
++
+ import java.io.File;
+ import java.io.FileInputStream;
+ import java.io.FileOutputStream;
+ import java.io.IOException;
+ import java.security.GeneralSecurityException;
+ import java.security.SecureRandom;
++
+ import org.apache.commons.io.IOUtils;
+ 
+ /**
+@@ -107,6 +110,12 @@ public class DefaultConfidentialStore extends ConfidentialStore {
+             return verifyMagic(bytes);
+         } catch (GeneralSecurityException e) {
+             throw new IOException("Failed to persist the key: "+key.getId(),e);
++        } catch (IOException x) {
++            if (x.getCause() instanceof BadPaddingException) {
++                return null; // broken somehow
++            } else {
++                throw x;
++            }
+         } finally {
+             IOUtils.closeQuietly(cis);
+             IOUtils.closeQuietly(fis);
+diff --git a/test/src/test/java/hudson/model/DownloadService2Test.java b/test/src/test/java/hudson/model/DownloadService2Test.java
+new file mode 100644
+index 0000000..b388b13
+--- /dev/null
++++ b/test/src/test/java/hudson/model/DownloadService2Test.java
+@@ -0,0 +1,65 @@
++/*
++ * The MIT License
++ *
++ * Copyright 2015 Jesse Glick.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++
++package hudson.model;
++
++import hudson.util.FormValidation;
++import java.net.URL;
++import java.util.Set;
++import java.util.TreeSet;
++import net.sf.json.JSONObject;
++import org.junit.Test;
++import static org.junit.Assert.*;
++import org.junit.Rule;
++import org.jvnet.hudson.test.Issue;
++import org.jvnet.hudson.test.JenkinsRule;
++import org.jvnet.hudson.test.WithoutJenkins;
++
++ at Issue("SECURITY-163")
++public class DownloadService2Test {
++
++    @Rule public JenkinsRule r = new JenkinsRule();
++
++    @Test public void updateNow() throws Exception {
++        for (DownloadService.Downloadable d : DownloadService.Downloadable.all()) {
++            FormValidation v = d.updateNow();
++            assertEquals(v.toString(), FormValidation.Kind.OK, v.kind);
++        }
++    }
++
++    @WithoutJenkins
++    @Test public void loadJSONHTML() throws Exception {
++        assertRoots("[list, signature]", "hudson.tasks.Maven.MavenInstaller.json.html"); // format used by most tools
++        assertRoots("[data, signature, version]", "hudson.tools.JDKInstaller.json.html"); // anomalous format
++    }
++
++    private static void assertRoots(String expected, String file) throws Exception {
++        URL resource = DownloadService2Test.class.getResource(file);
++        assertNotNull(file, resource);
++        JSONObject json = JSONObject.fromObject(DownloadService.loadJSONHTML(resource));
++        @SuppressWarnings("unchecked") Set<String> keySet = json.keySet();
++        assertEquals(expected, new TreeSet<String>(keySet).toString());
++    }
++
++}
+-- 
+2.1.0
+
diff --git a/0003-SECURITY-165-blacklist-the-document-xpath-function-f.patch b/0003-SECURITY-165-blacklist-the-document-xpath-function-f.patch
new file mode 100644
index 0000000..637ffba
--- /dev/null
+++ b/0003-SECURITY-165-blacklist-the-document-xpath-function-f.patch
@@ -0,0 +1,205 @@
+From d9560ae7a78f4bb03ce427359b7f8c7a148d2439 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Fri, 27 Mar 2015 15:00:02 +0100
+Subject: [PATCH 3/9] [SECURITY-165] blacklist the document xpath function for
+ use in Api
+
+---
+ core/src/main/java/hudson/model/Api.java           | 12 +++-
+ .../jenkins/util/xml/FilteredFunctionContext.java  | 77 ++++++++++++++++++++++
+ test/src/test/java/hudson/model/ApiTest.java       | 28 ++++++++
+ 3 files changed, 115 insertions(+), 2 deletions(-)
+ create mode 100644 core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java
+
+diff --git a/core/src/main/java/hudson/model/Api.java b/core/src/main/java/hudson/model/Api.java
+index c749f46..7372327 100644
+--- a/core/src/main/java/hudson/model/Api.java
++++ b/core/src/main/java/hudson/model/Api.java
+@@ -26,12 +26,14 @@ package hudson.model;
+ import hudson.ExtensionList;
+ import jenkins.model.Jenkins;
+ import jenkins.security.SecureRequester;
++import jenkins.util.xml.FilteredFunctionContext;
+ 
+ import org.dom4j.CharacterData;
+ import org.dom4j.Document;
+ import org.dom4j.DocumentException;
+ import org.dom4j.DocumentFactory;
+ import org.dom4j.Element;
++import org.dom4j.XPath;
+ import org.dom4j.io.SAXReader;
+ import org.dom4j.io.XMLWriter;
+ import org.kohsuke.stapler.QueryParameter;
+@@ -43,6 +45,7 @@ import org.kohsuke.stapler.export.TreePruner.ByDepth;
+ import javax.servlet.ServletException;
+ import javax.servlet.http.HttpServletResponse;
+ import javax.xml.transform.stream.StreamResult;
++
+ import java.io.IOException;
+ import java.io.OutputStream;
+ import java.io.StringReader;
+@@ -107,6 +110,7 @@ public class Api extends AbstractModelObject {
+         p.writeTo(bean,pruner,Flavor.XML.createDataWriter(bean,sw));
+ 
+         // apply XPath
++        FilteredFunctionContext functionContext = new FilteredFunctionContext();
+         Object result;
+         try {
+             Document dom = new SAXReader().read(new StringReader(sw.toString()));
+@@ -114,7 +118,9 @@ public class Api extends AbstractModelObject {
+             // apply exclusions
+             if (excludes!=null) {
+                 for (String exclude : excludes) {
+-                    List<org.dom4j.Node> list = (List<org.dom4j.Node>)dom.selectNodes(exclude);
++                    XPath xExclude = dom.createXPath(exclude);
++                    xExclude.setFunctionContext(functionContext);
++                    List<org.dom4j.Node> list = (List<org.dom4j.Node>) xExclude.selectNodes(dom);
+                     for (org.dom4j.Node n : list) {
+                         Element parent = n.getParent();
+                         if(parent!=null)
+@@ -126,7 +132,9 @@ public class Api extends AbstractModelObject {
+             if(xpath==null) {
+             	result = dom;
+             } else {
+-                List list = dom.selectNodes(xpath);
++                XPath comp = dom.createXPath(xpath);
++                comp.setFunctionContext(functionContext);
++                List list = comp.selectNodes(dom);
+                 if (wrapper!=null) {
+                     Element root = DocumentFactory.getInstance().createElement(wrapper);
+                     for (Object o : list) {
+diff --git a/core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java b/core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java
+new file mode 100644
+index 0000000..8104828
+--- /dev/null
++++ b/core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java
+@@ -0,0 +1,77 @@
++
++/*
++ * The MIT License
++ *
++ * Copyright (c) 2015, CloudBees, Inc. All rights reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++package jenkins.util.xml;
++
++import org.jaxen.Function;
++import org.jaxen.FunctionContext;
++import org.jaxen.UnresolvableException;
++import org.jaxen.XPathFunctionContext;
++import org.kohsuke.accmod.Restricted;
++import org.kohsuke.accmod.restrictions.NoExternalUse;
++
++import java.util.Arrays;
++import java.util.Collections;
++import java.util.HashSet;
++import java.util.Locale;
++import java.util.Set;
++
++/**
++ * {@link org.jaxen.FunctionContext} that removes some {@link org.dom4j.XPath}
++ * function names that are deemed bad as user input.
++ *
++ * @author Robert Sandell &lt;rsandell at cloudbees.com&gt;.
++ * @see org.jaxen.FunctionContext
++ * @see org.dom4j.XPath
++ * @see hudson.model.Api
++ */
++ at Restricted(NoExternalUse.class)
++public class FilteredFunctionContext implements FunctionContext {
++
++    /**
++     * Default set of "bad" function names.
++     */
++    private static final Set<String> DEFAULT_ILLEGAL_FUNCTIONS = Collections.unmodifiableSet(new HashSet<String>(
++            Arrays.asList("document")
++    ));
++    private final FunctionContext base;
++    private final Set<String> illegalFunctions;
++
++    public FilteredFunctionContext(Set<String> illegalFunctions) {
++        this.illegalFunctions = illegalFunctions;
++        base = XPathFunctionContext.getInstance();
++    }
++
++    public FilteredFunctionContext() {
++        this(DEFAULT_ILLEGAL_FUNCTIONS);
++    }
++
++    @Override
++    public Function getFunction(String namespaceURI, String prefix, String localName) throws UnresolvableException {
++        if (localName != null && illegalFunctions.contains(localName.toLowerCase(Locale.ENGLISH))) {
++            throw new UnresolvableException("Illegal function: " + localName);
++        }
++        return base.getFunction(namespaceURI, prefix, localName);
++    }
++}
+diff --git a/test/src/test/java/hudson/model/ApiTest.java b/test/src/test/java/hudson/model/ApiTest.java
+index 3b2d82f..a2a98cc 100644
+--- a/test/src/test/java/hudson/model/ApiTest.java
++++ b/test/src/test/java/hudson/model/ApiTest.java
+@@ -24,9 +24,14 @@
+ package hudson.model;
+ 
+ import com.gargoylesoftware.htmlunit.Page;
++
++import java.io.File;
++import java.io.IOException;
+ import java.net.HttpURLConnection;
++
+ import org.jvnet.hudson.test.HudsonTestCase;
+ import org.jvnet.hudson.test.Bug;
++import org.xml.sax.SAXException;
+ 
+ /**
+  * @author Kohsuke Kawaguchi
+@@ -38,6 +43,29 @@ public class ApiTest extends HudsonTestCase {
+         new WebClient().goTo("api/xml?xpath=/*[1]","application/xml");
+     }
+ 
++    /**
++     * Test that calling the xml API with the xpath document function fails.
++     *
++     * See SECURITY-165
++     *
++     * @throws IOException
++     *             if so
++     * @throws SAXException
++     *             if so
++     */
++    public void testXPathDocumentFunction() throws IOException, SAXException {
++        File f = new File(jenkins.getRootDir(), "queue.xml");
++        WebClient client = createWebClient();
++
++        try {
++            client.goTo("api/xml?xpath=document(\"" + f.getAbsolutePath() + "\")", "application/xml");
++            fail("Should become 500 error");
++        } catch (com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException e) {
++            String contentAsString = e.getResponse().getContentAsString();
++            assertStringContains(contentAsString, "Illegal function: document");
++        }
++    }
++
+     @Bug(3267)
+     public void testWrappedZeroItems() throws Exception {
+         Page page = new WebClient().goTo("api/xml?wrapper=root&xpath=/hudson/nonexistent", "application/xml");
+-- 
+2.1.0
+
diff --git a/0004-SECURITY-166-Prevent-the-creation-of-anonymous-syste.patch b/0004-SECURITY-166-Prevent-the-creation-of-anonymous-syste.patch
new file mode 100644
index 0000000..dc1cc89
--- /dev/null
+++ b/0004-SECURITY-166-Prevent-the-creation-of-anonymous-syste.patch
@@ -0,0 +1,381 @@
+From 94e089a5f4d2a8579cf1297bb22d6dbd9f617c67 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sat, 28 Mar 2015 16:32:51 +0100
+Subject: [PATCH 4/9] [SECURITY-166] Prevent the creation of anonymous, system
+ or unknown users.
+
+---
+ core/src/main/java/hudson/model/User.java          |  43 +++++++-
+ core/src/main/java/hudson/security/ACL.java        |  17 ++-
+ .../security/HudsonPrivateSecurityRealm.java       |   8 ++
+ .../resources/hudson/model/Messages.properties     |   4 +
+ .../security/HudsonPrivateSecurityRealm2Test.java  | 118 +++++++++++++++++++++
+ .../java/hudson/security/pages/SignupPage.java     |  65 ++++++++++++
+ 6 files changed, 251 insertions(+), 4 deletions(-)
+ create mode 100644 test/src/test/java/hudson/security/HudsonPrivateSecurityRealm2Test.java
+ create mode 100644 test/src/test/java/hudson/security/pages/SignupPage.java
+
+diff --git a/core/src/main/java/hudson/model/User.java b/core/src/main/java/hudson/model/User.java
+index c4190ee..b3c27b9 100644
+--- a/core/src/main/java/hudson/model/User.java
++++ b/core/src/main/java/hudson/model/User.java
+@@ -35,6 +35,7 @@ import hudson.security.Permission;
+ import hudson.security.SecurityRealm;
+ import hudson.security.UserMayOrMayNotExistException;
+ import hudson.util.FormApply;
++import hudson.util.FormValidation;
+ import hudson.util.RunList;
+ import hudson.util.XStream2;
+ import jenkins.model.IdStrategy;
+@@ -51,6 +52,8 @@ import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
+ import org.acegisecurity.userdetails.UserDetails;
+ import org.acegisecurity.userdetails.UsernameNotFoundException;
+ import org.springframework.dao.DataAccessException;
++import org.kohsuke.accmod.Restricted;
++import org.kohsuke.accmod.restrictions.NoExternalUse;
+ import org.kohsuke.stapler.StaplerRequest;
+ import org.kohsuke.stapler.StaplerResponse;
+ import org.kohsuke.stapler.export.Exported;
+@@ -109,7 +112,19 @@ import javax.annotation.Nullable;
+  */
+ @ExportedBean
+ public class User extends AbstractModelObject implements AccessControlled, DescriptorByNameOwner, Saveable, Comparable<User>, ModelObjectWithContextMenu {
++
++    /**
++     * The username of the 'unknown' user used to avoid null user references.
++     */
++    private static final String UKNOWN_USERNAME = "unknown";
+     
++    /**
++     * These usernames should not be used by real users logging into Jenkins. Therefore, we prevent
++     * users with these names from being saved.
++     */
++    private static final String[] ILLEGAL_PERSISTED_USERNAMES = new String[]{ACL.ANONYMOUS_USERNAME,
++            ACL.SYSTEM_USERNAME, UKNOWN_USERNAME};
++
+     private transient final String id;
+ 
+     private volatile String fullName;
+@@ -320,7 +335,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
+      * This is used to avoid null {@link User} instance.
+      */
+     public static @Nonnull User getUnknown() {
+-        return get("unknown");
++        return get(UKNOWN_USERNAME);
+     }
+ 
+     /**
+@@ -643,9 +658,33 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
+     }
+ 
+     /**
++     * Is the ID allowed? Some are prohibited for security reasons. See SECURITY-166.
++     * <p/>
++     * Note that this is only enforced when saving. These users are often created
++     * via the constructor (and even listed on /asynchPeople), but our goal is to
++     * prevent anyone from logging in as these users. Therefore, we prevent
++     * saving a User with one of these ids.
++     *
++     * @return true if the username or fullname is valid
++     */
++    public static boolean isIdOrFullnameAllowed(String id) {
++        for (String invalidId : ILLEGAL_PERSISTED_USERNAMES) {
++            if (id.equalsIgnoreCase(invalidId))
++                return false;
++        }
++        return true;
++    }
++
++    /**
+      * Save the settings to a file.
+      */
+-    public synchronized void save() throws IOException {
++    public synchronized void save() throws IOException, FormValidation {
++        if (!isIdOrFullnameAllowed(id)) {
++            throw FormValidation.error(Messages.User_IllegalUsername(id));
++        }
++        if (!isIdOrFullnameAllowed(fullName)) {
++            throw FormValidation.error(Messages.User_IllegalFullname(fullName));
++        }
+         if(BulkChange.contains(this))   return;
+         getConfigFile().write(this);
+         SaveableListener.fireOnChange(this, getConfigFile());
+diff --git a/core/src/main/java/hudson/security/ACL.java b/core/src/main/java/hudson/security/ACL.java
+index 2a1b230..f66fc86 100644
+--- a/core/src/main/java/hudson/security/ACL.java
++++ b/core/src/main/java/hudson/security/ACL.java
+@@ -35,6 +35,8 @@ import org.acegisecurity.context.SecurityContextHolder;
+ import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+ import org.acegisecurity.acls.sid.PrincipalSid;
+ import org.acegisecurity.acls.sid.Sid;
++import org.kohsuke.accmod.Restricted;
++import org.kohsuke.accmod.restrictions.NoExternalUse;
+ 
+ /**
+  * Gate-keeper that controls access to Hudson's model objects.
+@@ -96,22 +98,33 @@ public abstract class ACL {
+     };
+ 
+     /**
++     * The username for the anonymous user
++     */
++    @Restricted(NoExternalUse.class)
++    public static final String ANONYMOUS_USERNAME = "anonymous";
++    /**
+      * {@link Sid} that represents the anonymous unauthenticated users.
+      * <p>
+      * {@link HudsonFilter} sets this up, so this sid remains the same
+      * regardless of the current {@link SecurityRealm} in use.
+      */
+-    public static final Sid ANONYMOUS = new PrincipalSid("anonymous");
++    public static final Sid ANONYMOUS = new PrincipalSid(ANONYMOUS_USERNAME);
+ 
+     protected static final Sid[] AUTOMATIC_SIDS = new Sid[]{EVERYONE,ANONYMOUS};
+ 
+     /**
++     * The username for the system user
++     */
++    @Restricted(NoExternalUse.class)
++    public static final String SYSTEM_USERNAME = "SYSTEM";
++
++    /**
+      * {@link Sid} that represents the Hudson itself.
+      * <p>
+      * This is used when Hudson is performing computation for itself, instead
+      * of acting on behalf of an user, such as doing builds.
+      */
+-    public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken("SYSTEM","SYSTEM");
++    public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken(SYSTEM_USERNAME,"SYSTEM");
+ 
+     /**
+      * Changes the {@link Authentication} associated with the current thread
+diff --git a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
+index ef4b338..981a6e9 100644
+--- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
++++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
+@@ -337,6 +337,14 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
+         if(si.email==null || !si.email.contains("@"))
+             si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_InvalidEmailAddress();
+ 
++        if (!User.isIdOrFullnameAllowed(si.username)) {
++            si.errorMessage = hudson.model.Messages.User_IllegalUsername(si.username);
++        }
++
++        if (!User.isIdOrFullnameAllowed(si.fullname)) {
++            si.errorMessage = hudson.model.Messages.User_IllegalFullname(si.fullname);
++        }
++
+         if(si.errorMessage!=null) {
+             // failed. ask the user to try again.
+             req.setAttribute("data",si);
+diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties
+index b381d81..9721415 100644
+--- a/core/src/main/resources/hudson/model/Messages.properties
++++ b/core/src/main/resources/hudson/model/Messages.properties
+@@ -357,4 +357,8 @@ Jenkins.CheckDisplayName.NameNotUniqueWarning=The display name, "{0}", is used a
+ Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=The display name, "{0}", is already in use by another job and could cause confusion and delay.
+ 
+ Jenkins.NotAllowedName="{0}" is not allowed name
++
++User.IllegalUsername="{0}" is prohibited as a username for security reasons.
++User.IllegalFullname="{0}" is prohibited as a full name for security reasons.
++
+ Jenkins.IsRestarting=Jenkins is restarting
+diff --git a/test/src/test/java/hudson/security/HudsonPrivateSecurityRealm2Test.java b/test/src/test/java/hudson/security/HudsonPrivateSecurityRealm2Test.java
+new file mode 100644
+index 0000000..d42a475
+--- /dev/null
++++ b/test/src/test/java/hudson/security/HudsonPrivateSecurityRealm2Test.java
+@@ -0,0 +1,118 @@
++/*
++ * The MIT License
++ *
++ * Copyright (c) 2015, CloudBees, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++package hudson.security;
++
++import com.gargoylesoftware.htmlunit.html.HtmlPage;
++import hudson.model.User;
++import hudson.security.pages.SignupPage;
++import org.junit.Rule;
++import org.junit.Test;
++import org.jvnet.hudson.test.JenkinsRule;
++
++import java.util.Collections;
++
++import static org.hamcrest.Matchers.containsString;
++import static org.junit.Assert.*;
++import org.jvnet.hudson.test.Issue;
++
++/**
++ * Tests the signup page of {@link hudson.security.HudsonPrivateSecurityRealm}
++ * TODO: Add to {@link hudson.security.HudsonPrivateSecurityRealmTest} going forward
++ */
++public class HudsonPrivateSecurityRealm2Test {
++
++
++    @Rule
++    public JenkinsRule rule = new JenkinsRule();
++
++    @Test
++    public void signup() throws Exception {
++        HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(true, false, null);
++        rule.jenkins.setSecurityRealm(securityRealm);
++        JenkinsRule.WebClient wc = rule.createWebClient();
++        SignupPage signup = new SignupPage(wc.goTo("signup"));
++        signup.enterUsername("alice");
++        signup.enterPassword("alice");
++        signup.enterFullName("Alice User");
++        signup.enterEmail("alice at nowhere.com");
++        HtmlPage success = signup.submit(rule);
++        assertThat(success.getElementById("main-panel").getTextContent(), containsString("Success"));
++        assertThat(success.getAnchorByHref("/jenkins/user/alice").getTextContent(), containsString("Alice User"));
++
++
++        assertEquals("Alice User", securityRealm.getUser("alice").getDisplayName());
++
++    }
++
++    @Issue("SECURITY-166")
++    @Test
++    public void anonymousCantSignup() throws Exception {
++        HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(true, false, null);
++        rule.jenkins.setSecurityRealm(securityRealm);
++        JenkinsRule.WebClient wc = rule.createWebClient();
++        SignupPage signup = new SignupPage(wc.goTo("signup"));
++        signup.enterUsername("anonymous");
++        signup.enterFullName("Bob");
++        signup.enterPassword("nothing");
++        signup.enterEmail("noone at nowhere.com");
++        signup = new SignupPage(signup.submit(rule));
++        signup.assertErrorContains("prohibited as a username");
++        assertNull(User.get("anonymous", false, Collections.emptyMap()));
++    }
++
++    @Issue("SECURITY-166")
++    @Test
++    public void systemCantSignup() throws Exception {
++        HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(true, false, null);
++        rule.jenkins.setSecurityRealm(securityRealm);
++        JenkinsRule.WebClient wc = rule.createWebClient();
++        SignupPage signup = new SignupPage(wc.goTo("signup"));
++        signup.enterUsername("system");
++        signup.enterFullName("Bob");
++        signup.enterPassword("nothing");
++        signup.enterEmail("noone at nowhere.com");
++        signup = new SignupPage(signup.submit(rule));
++        signup.assertErrorContains("prohibited as a username");
++        assertNull(User.get("system",false, Collections.emptyMap()));
++    }
++
++    /**
++     * We don't allow prohibited fullnames since this may encumber auditing.
++     */
++    @Issue("SECURITY-166")
++    @Test
++    public void fullNameOfUnknownCantSignup() throws Exception {
++        HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(true, false, null);
++        rule.jenkins.setSecurityRealm(securityRealm);
++        JenkinsRule.WebClient wc = rule.createWebClient();
++        SignupPage signup = new SignupPage(wc.goTo("signup"));
++        signup.enterUsername("unknown2");
++        signup.enterPassword("unknown2");
++        signup.enterFullName("unknown");
++        signup.enterEmail("noone at nowhere.com");
++        signup = new SignupPage(signup.submit(rule));
++        signup.assertErrorContains("prohibited as a full name");
++        assertNull(User.get("unknown2",false, Collections.emptyMap()));
++    }
++}
+diff --git a/test/src/test/java/hudson/security/pages/SignupPage.java b/test/src/test/java/hudson/security/pages/SignupPage.java
+new file mode 100644
+index 0000000..5007bce
+--- /dev/null
++++ b/test/src/test/java/hudson/security/pages/SignupPage.java
+@@ -0,0 +1,65 @@
++package hudson.security.pages;
++
++import com.gargoylesoftware.htmlunit.html.HtmlForm;
++import com.gargoylesoftware.htmlunit.html.HtmlPage;
++import org.jvnet.hudson.test.JenkinsRule;
++
++import static org.hamcrest.Matchers.containsString;
++import static org.junit.Assert.*;
++
++/**
++ * The the signup page for {@link hudson.security.HudsonPrivateSecurityRealm}
++ */
++public class SignupPage {
++
++    public HtmlForm signupForm;
++    public final HtmlPage signupPage;
++
++    public SignupPage(HtmlPage signupPage) {
++        this.signupPage = signupPage;
++
++        assertNotNull("The sign up page has a username field.", this.signupPage.getElementById("username"));
++        for (HtmlForm signupForm : this.signupPage.getForms()) {
++            if (signupForm.getInputsByName("username").size() == 0)
++                continue;
++            this.signupForm = signupForm;
++        }
++
++    }
++
++
++
++    public void enterUsername(String username) {
++        signupForm.getInputByName("username").setValueAttribute(username);
++    }
++
++    /**
++     * Enters the password in password1 and password2.
++     * You can then call {@link #enterPassword2(String)} if you want them to be different.
++     * @param password
++     */
++    public void enterPassword(String password) {
++        signupForm.getInputByName("password1").setValueAttribute(password);
++        signupForm.getInputByName("password2").setValueAttribute(password);
++    }
++
++    public void enterPassword2(String password2) {
++        signupForm.getInputByName("password2").setValueAttribute(password2);
++    }
++
++    public void enterFullName(String fullName) {
++        signupForm.getInputByName("fullname").setValueAttribute(fullName);
++    }
++
++    public void enterEmail(String email) {
++        signupForm.getInputByName("email").setValueAttribute(email);
++    }
++
++    public HtmlPage submit(JenkinsRule rule) throws Exception {
++        return rule.submit(signupForm);
++    }
++
++    public void assertErrorContains(String msg) {
++        assertThat(signupForm.getElementById("main-panel").getTextContent(),containsString(msg));
++    }
++}
+-- 
+2.1.0
+
diff --git a/0005-SECURITY-167-defend-against-XXE-attacks.patch b/0005-SECURITY-167-defend-against-XXE-attacks.patch
new file mode 100644
index 0000000..f120c54
--- /dev/null
+++ b/0005-SECURITY-167-defend-against-XXE-attacks.patch
@@ -0,0 +1,581 @@
+From 6642805a1a54dfe1fe0c092b09ed4bdb9c849338 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sat, 28 Mar 2015 17:18:53 +0100
+Subject: [PATCH 5/9] [SECURITY-167] defend against XXE attacks.
+
+---
+ core/src/main/java/hudson/PluginManager.java       |  13 ++-
+ core/src/main/java/hudson/model/AbstractItem.java  |  21 ++---
+ core/src/main/java/hudson/model/View.java          |  16 ++--
+ .../util/xml/RestrictiveEntityResolver.java        |  32 +++++++
+ core/src/main/java/jenkins/util/xml/XMLUtils.java  |  99 ++++++++++++++++++++
+ core/src/test/java/hudson/PluginManagerTest.java   |  23 ++++-
+ core/src/test/java/jenkins/xml/XMLUtilsTest.java   | 100 +++++++++++++++++++++
+ .../hudson/model/AbstractItemSecurityTest.java     |  87 ++++++++++++++++++
+ 8 files changed, 370 insertions(+), 21 deletions(-)
+ create mode 100644 core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java
+ create mode 100644 core/src/main/java/jenkins/util/xml/XMLUtils.java
+ create mode 100644 core/src/test/java/jenkins/xml/XMLUtilsTest.java
+ create mode 100644 test/src/test/java/hudson/model/AbstractItemSecurityTest.java
+
+diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java
+index d2918a7..635509d 100644
+--- a/core/src/main/java/hudson/PluginManager.java
++++ b/core/src/main/java/hudson/PluginManager.java
+@@ -51,6 +51,7 @@ import jenkins.RestartRequiredException;
+ import jenkins.YesNoMaybe;
+ import jenkins.model.Jenkins;
+ import jenkins.util.io.OnMaster;
++import jenkins.util.xml.RestrictiveEntityResolver;
+ import net.sf.json.JSONArray;
+ import net.sf.json.JSONObject;
+ import org.apache.commons.fileupload.FileItem;
+@@ -109,6 +110,7 @@ import java.util.jar.Manifest;
+ import java.util.logging.Level;
+ import java.util.logging.Logger;
+ import org.xml.sax.Attributes;
++import org.xml.sax.InputSource;
+ import org.xml.sax.SAXException;
+ import org.xml.sax.helpers.DefaultHandler;
+ 
+@@ -1045,6 +1047,11 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
+                         requestedPlugins.put(shortName, requested);
+                     }
+                 }
++
++                @Override
++                public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
++                    return RestrictiveEntityResolver.INSTANCE.resolveEntity(publicId, systemId);
++                }
+             });
+         } catch (SAXException x) {
+             throw new IOException("Failed to parse XML",x);
+@@ -1237,9 +1244,9 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
+      */
+     @Extension
+     public static final class PluginUpdateMonitor extends AdministrativeMonitor {
+-        
+-        private Map<String, PluginUpdateInfo> pluginsToBeUpdated = new HashMap<String, PluginManager.PluginUpdateMonitor.PluginUpdateInfo>();
+-        
++
++        private Map<String, PluginUpdateInfo> pluginsToBeUpdated = new HashMap<String, PluginUpdateMonitor.PluginUpdateInfo>();
++
+         /**
+          * Convenience method to ease access to this monitor, this allows other plugins to register required updates.
+          * @return this monitor.
+diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java
+index 3524444..1ffbbf6 100644
+--- a/core/src/main/java/hudson/model/AbstractItem.java
++++ b/core/src/main/java/hudson/model/AbstractItem.java
+@@ -44,6 +44,7 @@ import hudson.util.IOUtils;
+ import jenkins.model.DirectlyModifiableTopLevelItemGroup;
+ import jenkins.model.Jenkins;
+ import jenkins.security.NotReallyRoleSensitiveCallable;
++import jenkins.util.xml.XMLUtils;
+ import org.acegisecurity.Authentication;
+ import org.apache.tools.ant.taskdefs.Copy;
+ import org.apache.tools.ant.types.FileSet;
+@@ -70,14 +71,13 @@ import org.kohsuke.stapler.interceptor.RequirePOST;
+ 
+ import javax.servlet.ServletException;
+ import javax.xml.transform.Source;
+-import javax.xml.transform.Transformer;
+ import javax.xml.transform.TransformerException;
+-import javax.xml.transform.TransformerFactory;
+ import javax.xml.transform.stream.StreamResult;
+ import javax.xml.transform.stream.StreamSource;
+ 
+ import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+ import org.kohsuke.stapler.Ancestor;
++import org.xml.sax.SAXException;
+ 
+ /**
+  * Partial default implementation of {@link Item}.
+@@ -628,24 +628,24 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
+ 
+     /**
+      * Updates Job by its XML definition.
++     * Updates an Item by its XML definition.
++     * @param source source of the Item's new definition.
++     *               The source should be either a <code>StreamSource</code> or a <code>SAXSource</code>, other
++     *               sources may not be handled.
+      * @since 1.473
+      */
+     public void updateByXml(Source source) throws IOException {
+         checkPermission(CONFIGURE);
+         XmlFile configXmlFile = getConfigFile();
+-        AtomicFileWriter out = new AtomicFileWriter(configXmlFile.getFile());
++        final AtomicFileWriter out = new AtomicFileWriter(configXmlFile.getFile());
+         try {
+             try {
+-                // this allows us to use UTF-8 for storing data,
+-                // plus it checks any well-formedness issue in the submitted
+-                // data
+-                Transformer t = TransformerFactory.newInstance()
+-                        .newTransformer();
+-                t.transform(source,
+-                        new StreamResult(out));
++                XMLUtils.safeTransform(source, new StreamResult(out));
+                 out.close();
+             } catch (TransformerException e) {
+                 throw new IOException("Failed to persist config.xml", e);
++            } catch (SAXException e) {
++                throw new IOException("Failed to persist config.xml", e);
+             }
+ 
+             // try to reflect the changes by reloading
+@@ -667,6 +667,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
+             // if everything went well, commit this new version
+             out.commit();
+             SaveableListener.fireOnChange(this, getConfigFile());
++
+         } finally {
+             out.abort(); // don't leave anything behind
+         }
+diff --git a/core/src/main/java/hudson/model/View.java b/core/src/main/java/hudson/model/View.java
+index d03727a..7e51719 100644
+--- a/core/src/main/java/hudson/model/View.java
++++ b/core/src/main/java/hudson/model/View.java
+@@ -58,6 +58,7 @@ import hudson.widgets.Widget;
+ import jenkins.model.Jenkins;
+ import jenkins.model.ModelObjectWithChildren;
+ import jenkins.util.ProgressiveRendering;
++import jenkins.util.xml.XMLUtils;
+ import net.sf.json.JSON;
+ import net.sf.json.JSONArray;
+ import net.sf.json.JSONObject;
+@@ -75,9 +76,7 @@ import org.kohsuke.stapler.interceptor.RequirePOST;
+ import javax.servlet.ServletException;
+ import javax.servlet.http.HttpServletResponse;
+ import javax.xml.transform.Source;
+-import javax.xml.transform.Transformer;
+ import javax.xml.transform.TransformerException;
+-import javax.xml.transform.TransformerFactory;
+ import javax.xml.transform.stream.StreamResult;
+ import javax.xml.transform.stream.StreamSource;
+ import java.io.BufferedInputStream;
+@@ -106,6 +105,7 @@ import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+ import static jenkins.model.Jenkins.*;
+ import org.kohsuke.accmod.Restricted;
+ import org.kohsuke.accmod.restrictions.NoExternalUse;
++import org.xml.sax.SAXException;
+ 
+ /**
+  * Encapsulates the rendering of the list of {@link TopLevelItem}s
+@@ -1063,7 +1063,10 @@ public abstract class View extends AbstractModelObject implements AccessControll
+     }
+ 
+     /**
+-     * Updates Job by its XML definition.
++     * Updates the View with the new XML definition.
++     * @param source source of the Item's new definition.
++     *               The source should be either a <code>StreamSource</code> or <code>SAXSource</code>, other sources
++     *               may not be handled.
+      */
+     public void updateByXml(Source source) throws IOException {
+         checkPermission(CONFIGURE);
+@@ -1072,13 +1075,12 @@ public abstract class View extends AbstractModelObject implements AccessControll
+             // this allows us to use UTF-8 for storing data,
+             // plus it checks any well-formedness issue in the submitted
+             // data
+-            Transformer t = TransformerFactory.newInstance()
+-                    .newTransformer();
+-            t.transform(source,
+-                    new StreamResult(out));
++            XMLUtils.safeTransform(source, new StreamResult(out));
+             out.close();
+         } catch (TransformerException e) {
+             throw new IOException("Failed to persist configuration.xml", e);
++        } catch (SAXException e) {
++            throw new IOException("Failed to persist configuration.xml", e);
+         }
+ 
+         // try to reflect the changes by reloading
+diff --git a/core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java b/core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java
+new file mode 100644
+index 0000000..1cf37c9
+--- /dev/null
++++ b/core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java
+@@ -0,0 +1,32 @@
++package jenkins.util.xml;
++
++import org.kohsuke.accmod.Restricted;
++import org.kohsuke.accmod.restrictions.NoExternalUse;
++import org.xml.sax.EntityResolver;
++import org.xml.sax.InputSource;
++import org.xml.sax.SAXException;
++
++import java.io.IOException;
++
++/**
++ * An EntityResolver that will fail to resolve any entities.
++ * Useful in preventing External XML Entity injection attacks.
++ */
++ at Restricted(NoExternalUse.class)
++public final class RestrictiveEntityResolver implements EntityResolver {
++
++    public final static RestrictiveEntityResolver INSTANCE = new RestrictiveEntityResolver();
++
++    private RestrictiveEntityResolver() {
++        // prevent multiple instantiation.
++        super();
++    }
++
++    /**
++     * Throws a SAXException if this tried to resolve any entity.
++     */
++    @Override
++    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
++        throw new SAXException("Refusing to resolve entity with publicId(" + publicId + ") and systemId (" + systemId + ")");
++    }
++}
+diff --git a/core/src/main/java/jenkins/util/xml/XMLUtils.java b/core/src/main/java/jenkins/util/xml/XMLUtils.java
+new file mode 100644
+index 0000000..84e6f61
+--- /dev/null
++++ b/core/src/main/java/jenkins/util/xml/XMLUtils.java
+@@ -0,0 +1,99 @@
++package jenkins.util.xml;
++
++import org.kohsuke.accmod.Restricted;
++import org.kohsuke.accmod.restrictions.NoExternalUse;
++import org.xml.sax.InputSource;
++import org.xml.sax.SAXException;
++import org.xml.sax.XMLReader;
++import org.xml.sax.helpers.XMLReaderFactory;
++
++import java.util.logging.Level;
++import java.util.logging.LogManager;
++import java.util.logging.Logger;
++import javax.annotation.Nonnull;
++import javax.xml.XMLConstants;
++import javax.xml.transform.Result;
++import javax.xml.transform.Source;
++import javax.xml.transform.Transformer;
++import javax.xml.transform.TransformerException;
++import javax.xml.transform.TransformerFactory;
++import javax.xml.transform.sax.SAXSource;
++import javax.xml.transform.sax.SAXTransformerFactory;
++
++/**
++ * Utilities useful when working with various XML types.
++ */
++ at Restricted(NoExternalUse.class)
++public final class XMLUtils {
++
++    private final static Logger LOGGER = LogManager.getLogManager().getLogger(XMLUtils.class.getName());
++    private final static String DISABLED_PROPERTY_NAME = XMLUtils.class.getName() + ".disableXXEPrevention";
++
++    /**
++     * Transform the source to the output in a manner that is protected against XXE attacks.
++     * If the transform can not be completed safely then an IOException is thrown.
++     * Note - to turn off safety set the system property <code>disableXXEPrevention</code> to <code>true</code>.
++     * @param source The XML input to transform. - This should be a <code>StreamSource</code> or a
++     *               <code>SAXSource</code> in order to be able to prevent XXE attacks.
++     * @param out The Result of transforming the <code>source</code>.
++     */
++    public static void safeTransform(@Nonnull Source source, @Nonnull Result out) throws TransformerException,
++            SAXException {
++
++        InputSource src = SAXSource.sourceToInputSource(source);
++        if (src != null) {
++            SAXTransformerFactory stFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
++            stFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
++
++            XMLReader xmlReader = XMLReaderFactory.createXMLReader();
++            try {
++                xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
++            }
++            catch (SAXException ignored) { /* ignored */ }
++            try {
++                xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
++            }
++            catch (SAXException ignored) { /* ignored */ }
++            // defend against XXE
++            // the above features should strip out entities - however the feature may not be supported depending
++            // on the xml implementation used and this is out of our control.
++            // So add a fallback plan if all else fails.
++            xmlReader.setEntityResolver(RestrictiveEntityResolver.INSTANCE);
++            SAXSource saxSource = new SAXSource(xmlReader, src);
++            _transform(saxSource, out);
++        }
++        else {
++            // for some reason we could not convert source
++            // this applies to DOMSource and StAXSource - and possibly 3rd party implementations...
++            // a DOMSource can already be compromised as it is parsed by the time it gets to us.
++            if (Boolean.getBoolean(DISABLED_PROPERTY_NAME)) {
++                LOGGER.log(Level.WARNING,  "XML external entity (XXE) prevention has been disabled by the system " +
++                        "property {0}=true Your system may be vulnerable to XXE attacks.", DISABLED_PROPERTY_NAME);
++                if (LOGGER.isLoggable(Level.FINE)) {
++                    LOGGER.log(Level.FINE, "Caller stack trace: ", new Exception("XXE Prevention caller history"));
++                }
++                _transform(source, out);
++            }
++            else {
++                throw new TransformerException("Could not convert source of type " + source.getClass() + " and " +
++                        "XXEPrevention is enabled.");
++            }
++        }
++    }
++
++    /**
++     * potentially unsafe XML transformation.
++     * @param source The XML input to transform.
++     * @param out The Result of transforming the <code>source</code>.
++     */
++    private static void _transform(Source source, Result out) throws TransformerException {
++        TransformerFactory factory = TransformerFactory.newInstance();
++        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
++
++        // this allows us to use UTF-8 for storing data,
++        // plus it checks any well-formedness issue in the submitted data.
++        Transformer t = factory.newTransformer();
++        t.transform(source, out);
++    }
++
++}
+diff --git a/core/src/test/java/hudson/PluginManagerTest.java b/core/src/test/java/hudson/PluginManagerTest.java
+index cbda285..6323fe0 100644
+--- a/core/src/test/java/hudson/PluginManagerTest.java
++++ b/core/src/test/java/hudson/PluginManagerTest.java
+@@ -26,16 +26,37 @@ package hudson;
+ 
+ import org.apache.tools.ant.filters.StringInputStream;
+ import org.junit.Test;
++import org.xml.sax.SAXException;
+ 
+-import java.io.File;
++import java.io.IOException;
+ 
++import static org.hamcrest.core.IsInstanceOf.instanceOf;
++import static org.hamcrest.core.StringContains.containsString;
+ import static org.junit.Assert.*;
+ 
+ public class PluginManagerTest {
+ 
++
+     @Test public void parseRequestedPlugins() throws Exception {
+         assertEquals("{other=2.0, stuff=1.2}", new LocalPluginManager(Util.createTempDir())
+                 .parseRequestedPlugins(new StringInputStream("<root><stuff plugin='stuff at 1.0'><more plugin='other at 2.0'><things plugin='stuff at 1.2'/></more></stuff></root>")).toString());
+     }
+ 
++    @Test
++    public void parseInvalidRequestedPlugins() throws Exception {
++        String evilXML = "<?xml version='1.0' encoding='UTF-8'?>\n"
++                + "<!DOCTYPE project[<!ENTITY foo SYSTEM \"file:///\">]>\n" + "<root>\n"
++                + "  <stuff plugin='stuff at 1.0'>\n" + "&foo;" + "    <more plugin='other at 2.0'>\n"
++                + "      <things plugin='stuff at 1.2'/>\n" + "    </more>\n" + "  </stuff>\n" + "</root>\n";
++
++        PluginManager pluginManager = new LocalPluginManager(Util.createTempDir());
++        try {
++            pluginManager.parseRequestedPlugins(new StringInputStream(evilXML));
++            fail("XML contains an external entity, but no exception was thrown.");
++        } catch (IOException ex) {
++            assertThat(ex.getCause(), instanceOf(SAXException.class));
++            assertThat(ex.getCause().getMessage(),
++                    containsString("Refusing to resolve entity with publicId(null) and systemId (file:///)"));
++        }
++    }
+ }
+diff --git a/core/src/test/java/jenkins/xml/XMLUtilsTest.java b/core/src/test/java/jenkins/xml/XMLUtilsTest.java
+new file mode 100644
+index 0000000..b71700b
+--- /dev/null
++++ b/core/src/test/java/jenkins/xml/XMLUtilsTest.java
+@@ -0,0 +1,100 @@
++/*
++ * The MIT License
++ *
++ * Copyright 2015 James Nord.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++
++package jenkins.xml;
++
++import jenkins.util.xml.XMLUtils;
++
++import org.junit.Test;
++
++import java.io.StringReader;
++import java.io.StringWriter;
++import javax.xml.transform.TransformerException;
++import javax.xml.transform.stream.StreamResult;
++import javax.xml.transform.stream.StreamSource;
++
++import static org.hamcrest.core.StringContains.containsString;
++import static org.junit.Assert.assertThat;
++import org.jvnet.hudson.test.Issue;
++
++public class XMLUtilsTest {
++
++    @Issue("SECURITY-167")
++    @Test()
++    public void testSafeTransformDoesNotProcessForeignResources() throws Exception {
++        final String xml = "<?xml version='1.0' encoding='UTF-8'?>\n" +
++                "<!DOCTYPE project[\n" +
++                "  <!ENTITY foo SYSTEM \"file:///\">\n" +
++                "]>\n" +
++                "<project>\n" +
++                "  <actions/>\n" +
++                "  <description>&foo;</description>\n" +
++                "  <keepDependencies>false</keepDependencies>\n" +
++                "  <properties/>\n" +
++                "  <scm class=\"hudson.scm.NullSCM\"/>\n" +
++                "  <canRoam>true</canRoam>\n" +
++                "  <triggers/>\n" +
++                "  <builders/>\n" +
++                "  <publishers/>\n" +
++                "  <buildWrappers/>\n" +
++                "</project>";
++
++
++        StringWriter stringWriter = new StringWriter();
++        try {
++            XMLUtils.safeTransform(new StreamSource(new StringReader(xml)), new StreamResult(stringWriter));
++            // if no exception then JAXP is swallowing these - so there should be no entity in the description.
++            assertThat(stringWriter.toString(), containsString("<description/>"));
++        } catch (TransformerException ex) {
++            assertThat(ex.getMessage(), containsString("Refusing to resolve entity"));
++        }
++
++    }
++
++
++    @Issue("SECURITY-167")
++    @Test()
++    public void testUpdateByXmlIDoesNotFail() throws Exception {
++        final String xml = "<?xml version='1.0' encoding='UTF-8'?>\n" +
++                "<project>\n" +
++                "  <actions/>\n" +
++                "  <description>&amp;</description>\n" +
++                "  <keepDependencies>false</keepDependencies>\n" +
++                "  <properties/>\n" +
++                "  <scm class=\"hudson.scm.NullSCM\"/>\n" +
++                "  <canRoam>true</canRoam>\n" +
++                "  <triggers/>\n" +
++                "  <builders/>\n" +
++                "  <publishers/>\n" +
++                "  <buildWrappers/>\n" +
++                "</project>";
++
++        StringWriter stringWriter = new StringWriter();
++
++        XMLUtils.safeTransform(new StreamSource(new StringReader(xml)), new StreamResult(stringWriter));
++        // make sure that normal entities are retained.
++        assertThat(stringWriter.toString(), containsString("<description>&amp;</description>"));
++    }
++
++}
+diff --git a/test/src/test/java/hudson/model/AbstractItemSecurityTest.java b/test/src/test/java/hudson/model/AbstractItemSecurityTest.java
+new file mode 100644
+index 0000000..653097d
+--- /dev/null
++++ b/test/src/test/java/hudson/model/AbstractItemSecurityTest.java
+@@ -0,0 +1,87 @@
++/*
++ * The MIT License
++ *
++ * Copyright 2015 James Nord.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++
++package hudson.model;
++
++import org.junit.Rule;
++import org.junit.Test;
++import org.jvnet.hudson.test.JenkinsRule;
++import javax.xml.transform.stream.StreamSource;
++import java.io.IOException;
++import java.io.StringReader;
++
++import static org.hamcrest.core.Is.is;
++import static org.hamcrest.core.IsNot.not;
++import static org.hamcrest.core.IsNull.nullValue;
++import static org.hamcrest.core.StringContains.containsString;
++import static org.hamcrest.text.IsEmptyString.isEmptyOrNullString;
++import static org.junit.Assert.assertThat;
++import org.jvnet.hudson.test.Issue;
++
++public class AbstractItemSecurityTest {
++
++    @Rule
++    public JenkinsRule jenkinsRule = new JenkinsRule();
++
++    @Issue("SECURITY-167")
++    @Test()
++    public void testUpdateByXmlDoesNotProcessForeignResources() throws Exception {
++        final String xml = "<?xml version='1.0' encoding='UTF-8'?>\n" +
++                "<!DOCTYPE project[\n" +
++                "  <!ENTITY foo SYSTEM \"file:///\">\n" +
++                "]>\n" +
++                "<project>\n" +
++                "  <description>&foo;</description>\n" +
++                "  <scm class=\"hudson.scm.NullSCM\"/>\n" +
++                "</project>";
++
++        FreeStyleProject project = jenkinsRule.createFreeStyleProject("security-167");
++        project.setDescription("Wibble");
++        try {
++            project.updateByXml(new StreamSource(new StringReader(xml)));
++            // if we didn't fail JAXP has thrown away the entity.
++            assertThat(project.getDescription(), isEmptyOrNullString());
++        } catch (IOException ex) {
++            assertThat(ex.getCause(), not(nullValue()));
++            assertThat(ex.getCause().getMessage(), containsString("Refusing to resolve entity"));
++        }
++
++    }
++
++
++    @Issue("SECURITY-167")
++    @Test()
++    public void testUpdateByXmlDoesNotFail() throws Exception {
++        final String xml = "<?xml version='1.0' encoding='UTF-8'?>\n" +
++                "<project>\n" +
++                "  <description>&amp;</description>\n" +
++                "  <scm class=\"hudson.scm.NullSCM\"/>\n" +
++                "</project>";
++
++        FreeStyleProject project = jenkinsRule.createFreeStyleProject("security-167");
++        project.updateByXml((StreamSource) new StreamSource(new StringReader(xml)));
++        assertThat(project.getDescription(), is("&")); // the entity is transformed
++    }
++
++}
+-- 
+2.1.0
+
diff --git a/0006-SECURITY-125-Preventing-cyclic-dependencies-among-bu.patch b/0006-SECURITY-125-Preventing-cyclic-dependencies-among-bu.patch
new file mode 100644
index 0000000..18bc055
--- /dev/null
+++ b/0006-SECURITY-125-Preventing-cyclic-dependencies-among-bu.patch
@@ -0,0 +1,62 @@
+From 308d394ccd57a2d5b1b44565be9808a5248cb0af Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sat, 28 Mar 2015 17:50:02 +0100
+Subject: [PATCH 6/9] [SECURITY-125] Preventing cyclic dependencies among
+ bundled plugins.
+
+---
+ core/src/main/java/hudson/ClassicPluginStrategy.java | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java
+index 75d1414..5609152 100644
+--- a/core/src/main/java/hudson/ClassicPluginStrategy.java
++++ b/core/src/main/java/hudson/ClassicPluginStrategy.java
+@@ -64,6 +64,7 @@ import java.util.Collections;
+ import java.util.Enumeration;
+ import java.util.HashSet;
+ import java.util.List;
++import java.util.Set;
+ import java.util.Vector;
+ import java.util.jar.Attributes;
+ import java.util.jar.JarFile;
+@@ -287,13 +288,19 @@ public class ClassicPluginStrategy implements PluginStrategy {
+             // don't fix the dependency for yourself, or else we'll have a cycle
+             String yourName = atts.getValue("Short-Name");
+             if (shortName.equals(yourName))   return;
++            if (BREAK_CYCLES.contains(yourName + '/' + shortName)) {
++                LOGGER.log(Level.FINE, "skipping implicit dependency {0} → {1}", new Object[] { yourName, shortName });
++                return;
++            }
+ 
+             // some earlier versions of maven-hpi-plugin apparently puts "null" as a literal in Hudson-Version. watch out for them.
+             String jenkinsVersion = atts.getValue("Jenkins-Version");
+             if (jenkinsVersion==null)
+                 jenkinsVersion = atts.getValue("Hudson-Version");
+-            if (jenkinsVersion == null || jenkinsVersion.equals("null") || new VersionNumber(jenkinsVersion).compareTo(splitWhen) <= 0)
+-                optionalDependencies.add(new PluginWrapper.Dependency(shortName+':'+requireVersion));
++            if (jenkinsVersion == null || jenkinsVersion.equals("null") || new VersionNumber(jenkinsVersion).compareTo(splitWhen) <= 0) {
++                optionalDependencies.add(new PluginWrapper.Dependency(shortName + ':' + requireVersion));
++                LOGGER.log(Level.FINE, "adding implicit dependency {0} → {1} because of {2}", new Object[] { yourName, shortName, jenkinsVersion });
++            }
+         }
+     }
+ 
+@@ -314,6 +321,14 @@ public class ClassicPluginStrategy implements PluginStrategy {
+         new DetachedPlugin("junit","1.577.*","1.0")
+     );
+ 
++    /** Implicit dependencies that are known to be unnecessary and which must be cut out to prevent a dependency cycle among bundled plugins. */
++    private static final Set<String> BREAK_CYCLES = new HashSet<String>(Arrays.asList(
++            "script-security/matrix-auth",
++            "script-security/windows-slaves",
++            "script-security/antisamy-markup-formatter",
++            "script-security/matrix-project"
++    ));
++
+     /**
+      * Computes the classloader that takes the class masking into account.
+      *
+-- 
+2.1.0
+
diff --git a/0007-SECURITY-171-XSS-in-FormValidation._error-.-Throwabl.patch b/0007-SECURITY-171-XSS-in-FormValidation._error-.-Throwabl.patch
new file mode 100644
index 0000000..7b1167b
--- /dev/null
+++ b/0007-SECURITY-171-XSS-in-FormValidation._error-.-Throwabl.patch
@@ -0,0 +1,52 @@
+From 67e668d93f0c6594d03bd3c7608f2e766497e74d Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sat, 28 Mar 2015 17:58:36 +0100
+Subject: [PATCH 7/9] [SECURITY-171] XSS in FormValidation._error(...,
+ Throwable, ...)
+
+---
+ core/src/main/java/hudson/util/FormValidation.java     | 2 +-
+ core/src/test/java/hudson/util/FormValidationTest.java | 9 +++++++++
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/core/src/main/java/hudson/util/FormValidation.java b/core/src/main/java/hudson/util/FormValidation.java
+index 12b6c06..ac471cb 100644
+--- a/core/src/main/java/hudson/util/FormValidation.java
++++ b/core/src/main/java/hudson/util/FormValidation.java
+@@ -199,7 +199,7 @@ public abstract class FormValidation extends IOException implements HttpResponse
+             " <a href='#' class='showDetails'>"
+             + Messages.FormValidation_Error_Details()
+             + "</a><pre style='display:none'>"
+-            + Functions.printThrowable(e) +
++            + Util.escape(Functions.printThrowable(e)) +
+             "</pre>",kind
+         );
+     }
+diff --git a/core/src/test/java/hudson/util/FormValidationTest.java b/core/src/test/java/hudson/util/FormValidationTest.java
+index f5c18f4..d8f58fd 100644
+--- a/core/src/test/java/hudson/util/FormValidationTest.java
++++ b/core/src/test/java/hudson/util/FormValidationTest.java
+@@ -23,6 +23,10 @@
+  */
+ package hudson.util;
+ 
++import static org.hamcrest.CoreMatchers.containsString;
++import static org.hamcrest.CoreMatchers.not;
++import static org.hamcrest.MatcherAssert.assertThat;
++
+ import static org.junit.Assert.*;
+ 
+ import java.util.Arrays;
+@@ -105,4 +109,9 @@ public class FormValidationTest {
+     private FormValidation aggregate(FormValidation... fvs) {
+         return FormValidation.aggregate(Arrays.asList(fvs));
+     }
++
++    public void testFormValidationException() {
++        FormValidation fv = FormValidation.error(new Exception("<html"), "Message<html");
++        assertThat(fv.renderHtml(), not(containsString("<html")));
++    }
+ }
+-- 
+2.1.0
+
diff --git a/0008-SECURITY-177-Reflected-XSS-in-AdjunctManager.doDynam.patch b/0008-SECURITY-177-Reflected-XSS-in-AdjunctManager.doDynam.patch
new file mode 100644
index 0000000..830d96d
--- /dev/null
+++ b/0008-SECURITY-177-Reflected-XSS-in-AdjunctManager.doDynam.patch
@@ -0,0 +1,80 @@
+From e08e09d4226cc2ec9b29d385d629fbf140806565 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sat, 28 Mar 2015 18:06:57 +0100
+Subject: [PATCH 8/9] [SECURITY-177] Reflected XSS in AdjunctManager.doDynamic
+
+---
+ .../main/java/hudson/security/HudsonFilter.java    |  6 +++-
+ .../java/jenkins/security/Security177Test.java     | 36 ++++++++++++++++++++++
+ 2 files changed, 41 insertions(+), 1 deletion(-)
+ create mode 100644 test/src/test/java/jenkins/security/Security177Test.java
+
+diff --git a/core/src/main/java/hudson/security/HudsonFilter.java b/core/src/main/java/hudson/security/HudsonFilter.java
+index 40c7e7c..a92b984 100644
+--- a/core/src/main/java/hudson/security/HudsonFilter.java
++++ b/core/src/main/java/hudson/security/HudsonFilter.java
+@@ -36,6 +36,7 @@ import javax.servlet.ServletContext;
+ import javax.servlet.ServletException;
+ import javax.servlet.ServletRequest;
+ import javax.servlet.ServletResponse;
++import javax.servlet.http.HttpServletResponse;
+ 
+ import org.acegisecurity.AuthenticationManager;
+ import org.acegisecurity.ui.rememberme.RememberMeServices;
+@@ -153,7 +154,10 @@ public class HudsonFilter implements Filter {
+ 
+     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+         LOGGER.entering(HudsonFilter.class.getName(), "doFilter");
+-        
++
++        // this is not the best place to do it, but doing it here makes the patch smaller.
++        ((HttpServletResponse) response).setHeader("X-Content-Type-Options", "nosniff");
++
+         // to deal with concurrency, we need to capture the object.
+         Filter f = filter;
+ 
+diff --git a/test/src/test/java/jenkins/security/Security177Test.java b/test/src/test/java/jenkins/security/Security177Test.java
+new file mode 100644
+index 0000000..beaf949
+--- /dev/null
++++ b/test/src/test/java/jenkins/security/Security177Test.java
+@@ -0,0 +1,36 @@
++package jenkins.security;
++
++import com.gargoylesoftware.htmlunit.Page;
++import java.net.URL;
++import static org.junit.Assert.assertEquals;
++import org.junit.Rule;
++import org.junit.Test;
++import org.jvnet.hudson.test.Issue;
++import org.jvnet.hudson.test.JenkinsRule;
++import org.jvnet.hudson.test.JenkinsRule.WebClient;
++
++/**
++ * @author Kohsuke Kawaguchi
++ */
++ at Issue("SECURITY-177")
++public class Security177Test {
++    @Rule
++    public JenkinsRule jenkins = new JenkinsRule();
++
++    @Test
++    public void nosniff() throws Exception {
++        WebClient wc = jenkins.createWebClient();
++        wc.setThrowExceptionOnFailingStatusCode(false);
++
++        URL u = jenkins.getURL();
++        verifyNoSniff(wc.getPage(new URL(u, "adjuncts/507db12b/nosuch/adjunct.js")));
++        verifyNoSniff(wc.getPage(new URL(u, "no-such-page")));
++        verifyNoSniff(wc.getPage(new URL(u, "images/title.svg")));
++        verifyNoSniff(wc.getPage(u));
++    }
++
++    private void verifyNoSniff(Page p) {
++        String v = p.getWebResponse().getResponseHeaderValue("X-Content-Type-Options");
++        assertEquals(v,"nosniff");
++    }
++}
+-- 
+2.1.0
+
diff --git a/0009-SECURITY-180-arbitrary-API-Token-change-leak-via-cha.patch b/0009-SECURITY-180-arbitrary-API-Token-change-leak-via-cha.patch
new file mode 100644
index 0000000..a512e48
--- /dev/null
+++ b/0009-SECURITY-180-arbitrary-API-Token-change-leak-via-cha.patch
@@ -0,0 +1,121 @@
+From ff3b7edd412744e9f357a102633e465f30086b81 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sat, 28 Mar 2015 18:22:12 +0100
+Subject: [PATCH 9/9] [SECURITY-180] arbitrary API Token change/leak via
+ changeToken
+
+---
+ .../java/jenkins/security/ApiTokenProperty.java    |  1 +
+ .../groovy/hudson/model/UpdateCenter2Test.groovy   |  2 +-
+ test/src/test/java/hudson/model/UserTest.java      | 46 ++++++++++++++++++++++
+ 3 files changed, 48 insertions(+), 1 deletion(-)
+
+diff --git a/core/src/main/java/jenkins/security/ApiTokenProperty.java b/core/src/main/java/jenkins/security/ApiTokenProperty.java
+index caa9ed8..124d8bd 100644
+--- a/core/src/main/java/jenkins/security/ApiTokenProperty.java
++++ b/core/src/main/java/jenkins/security/ApiTokenProperty.java
+@@ -81,6 +81,7 @@ public class ApiTokenProperty extends UserProperty {
+     }
+ 
+     public void changeApiToken() throws IOException {
++        user.checkPermission(Jenkins.ADMINISTER);
+         _changeApiToken();
+         if (user!=null)
+             user.save();
+diff --git a/test/src/test/groovy/hudson/model/UpdateCenter2Test.groovy b/test/src/test/groovy/hudson/model/UpdateCenter2Test.groovy
+index 6a1a5ad..f0b8f8a 100644
+--- a/test/src/test/groovy/hudson/model/UpdateCenter2Test.groovy
++++ b/test/src/test/groovy/hudson/model/UpdateCenter2Test.groovy
+@@ -46,7 +46,7 @@ public class UpdateCenter2Test {
+     @RandomlyFails("SocketTimeoutException from goTo due to GET http://localhost:…/update-center.json?…")
+     @Test void install() {
+         UpdateSite.neverUpdate = false;
+-        j.createWebClient().goTo("") // load the metadata
++        j.jenkins.pluginManager.doCheckUpdatesServer(); // load the metadata
+         def job = j.jenkins.updateCenter.getPlugin("changelog-history").deploy().get(); // this seems like one of the smallest plugin
+         println job.status;
+         assertTrue(job.status instanceof Success)
+diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java
+index 9509b8e..c4f123a 100644
+--- a/test/src/test/java/hudson/model/UserTest.java
++++ b/test/src/test/java/hudson/model/UserTest.java
+@@ -28,11 +28,13 @@ import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
+ import com.gargoylesoftware.htmlunit.WebAssert;
+ import com.gargoylesoftware.htmlunit.html.HtmlForm;
+ import com.gargoylesoftware.htmlunit.html.HtmlPage;
++
+ import hudson.security.AccessDeniedException2;
+ import hudson.security.GlobalMatrixAuthorizationStrategy;
+ import hudson.security.HudsonPrivateSecurityRealm;
+ import hudson.security.Permission;
+ import hudson.tasks.MailAddressResolver;
++
+ import java.io.File;
+ import java.io.IOException;
+ import java.io.PrintStream;
+@@ -41,11 +43,16 @@ import java.util.Collections;
+ 
+ import jenkins.model.IdStrategy;
+ import jenkins.model.Jenkins;
++import jenkins.security.ApiTokenProperty;
++
++import org.acegisecurity.AccessDeniedException;
+ import org.acegisecurity.Authentication;
+ import org.acegisecurity.context.SecurityContext;
+ import org.acegisecurity.context.SecurityContextHolder;
++
+ import static org.junit.Assert.*;
+ import static org.junit.Assume.*;
++
+ import org.junit.Rule;
+ import org.junit.Test;
+ import org.jvnet.hudson.test.Bug;
+@@ -498,6 +505,45 @@ public class UserTest {
+         assertTrue("But once storage is allocated, he can be deleted", user3.canDelete());
+     }
+ 
++    @Test
++    // @Issue("SECURITY-180")
++    public void security180() throws Exception {
++        final GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
++        j.jenkins.setAuthorizationStrategy(auth);
++        j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
++
++        User alice = User.get("alice");
++        User bob = User.get("bob");
++        User admin = User.get("admin");
++
++        auth.add(Jenkins.READ, alice.getId());
++        auth.add(Jenkins.READ, bob.getId());
++        auth.add(Jenkins.ADMINISTER, admin.getId());
++
++        // Admin can change everyone's token
++        SecurityContextHolder.getContext().setAuthentication(admin.impersonate());
++        admin.getProperty(ApiTokenProperty.class).changeApiToken();
++        alice.getProperty(ApiTokenProperty.class).changeApiToken();
++
++        // User can change only own token
++        SecurityContextHolder.getContext().setAuthentication(bob.impersonate());
++        bob.getProperty(ApiTokenProperty.class).changeApiToken();
++
++        try {
++            alice.getProperty(ApiTokenProperty.class).changeApiToken();
++            fail("Bob should not be authorized to change alice's token");
++        } catch (AccessDeniedException expected) {
++        }
++
++        // ANONYMOUS can not change any token
++        SecurityContextHolder.getContext().setAuthentication(Jenkins.ANONYMOUS);
++        try {
++            alice.getProperty(ApiTokenProperty.class).changeApiToken();
++            fail("Anonymous should not be authorized to change alice's token");
++        } catch (AccessDeniedException expected) {
++        }
++    }
++
+      public static class SomeUserProperty extends UserProperty {
+          
+         @TestExtension
+-- 
+2.1.0
+
diff --git a/jenkins.spec b/jenkins.spec
index fb5b012..5d000f8 100644
--- a/jenkins.spec
+++ b/jenkins.spec
@@ -11,7 +11,7 @@
 
 Name:           jenkins
 Version:        1.590
-Release:        2%{?dist}
+Release:        3%{?dist}
 Summary:        An extendable open source continuous integration server
 
 # The project's primary license is MIT
@@ -32,6 +32,16 @@ Source6:        jenkins.service
 Source7:        jenkins.init
 Source8:        dependencies.txt
 
+Patch101:       0001-SECURITY-162-Capture-the-root-directory-in-VirtualFi.patch
+Patch102:       0002-SECURITY-163-Treat-BadPaddingException-as-an-unloada.patch
+Patch103:       0003-SECURITY-165-blacklist-the-document-xpath-function-f.patch
+Patch104:       0004-SECURITY-166-Prevent-the-creation-of-anonymous-syste.patch
+Patch105:       0005-SECURITY-167-defend-against-XXE-attacks.patch
+Patch106:       0006-SECURITY-125-Preventing-cyclic-dependencies-among-bu.patch
+Patch107:       0007-SECURITY-171-XSS-in-FormValidation._error-.-Throwabl.patch
+Patch108:       0008-SECURITY-177-Reflected-XSS-in-AdjunctManager.doDynam.patch
+Patch109:       0009-SECURITY-180-arbitrary-API-Token-change-leak-via-cha.patch
+
 # animal sniffer is not really useful in Fedora
 Patch1:         remove-animal-sniffer-annotations.patch
 #Patch2:         remove-support-for-solaris.patch
@@ -383,6 +393,16 @@ This package contains API documentation for %{name}.
 %prep
 %setup -q -n %{name}-%{name}-%{version}
 
+%patch101 -p1
+%patch102 -p1
+%patch103 -p1
+%patch104 -p1
+%patch105 -p1
+%patch106 -p1
+%patch107 -p1
+%patch108 -p1
+%patch109 -p1
+
 %patch1 -p1
 %patch3 -p1
 %patch4 -p1
@@ -391,7 +411,7 @@ This package contains API documentation for %{name}.
 %patch9 -p1
 %patch10 -p1
 %patch11 -p1
-%patch13 -p1
+%patch13 -p1 -F2
 %patch14 -p1
 
 # Remove bundled JARs and classes
@@ -729,6 +749,18 @@ exit 0
 %doc LICENSE.txt
 
 %changelog
+* Sun Mar 29 2015 Michal Srb <msrb at redhat.com> - 1.590-3
+- Fix multiple CVEs:
+- Resolves: CVE-2015-1806
+- Resolves: CVE-2015-1807
+- Resolves: CVE-2015-1813
+- Resolves: CVE-2015-1812
+- Resolves: CVE-2015-1810
+- Resolves: CVE-2015-1808
+- Resolves: CVE-2015-1809
+- Resolves: CVE-2015-1814
+- Resolves: CVE-2015-1811
+
 * Mon Feb 02 2015 Michal Srb <msrb at redhat.com> - 1.590-2
 - Require jna >= 4.1.0-7
 
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/jenkins.git/commit/?h=f21&id=e51239c00ee63ff7a373990cc962b2fd9063b7ab


More information about the scm-commits mailing list