CVE-2014-9635: 7PK - Security Features (CWE-254)
value: Jenkins before 1.586 does not set the HttpOnly flag in a Set-Cookie header for session cookies when run on Tomcat 7.0.41 or later, which makes it easier for remote attackers to obtain potentially sensitive information via script access to cookies.
CWE description: Software security is not security software. Here we're concerned with topics like authentication, access control, confidentiality, cryptography, and privilege management.
CVSS v3 base score: 5.3
Published: 2017-09-12T14:29Z
Repository: https://github.com/jenkinsci/jenkins
Language: Java
Files changed: changelog.html, core/src/main/java/hudson/WebAppMain.java, core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
Commit date: 2014-10-16 19:23:23 -0700
Commit message: [FIXED JENKINS-25019]

A truly conforming servlet 3.0 container does not allow us to set "secure cookie" flag beyond ServletContextListener.onInitialized().
If we see that, don't scare the users.

Diff: diff --git a/changelog.html b/changelog.html
index d8a3ebc75a..96236f78f9 100644
--- a/changelog.html
+++ b/changelog.html
@@ -59,10 +59,14 @@ Upcoming changes</a>
     Bumping up JNA to 4.10. This is potentially a breaking change for plugins that depend on JNA 3.x
     (<a href="https://issues.jenkins-ci.org/browse/JENKINS-24521">issue 24521</a>)
   <li class=bug>
     Prevent empty file creation if file parameter is left empty.
     (<a href="https://issues.jenkins-ci.org/browse/JENKINS-3539">issue 3539</a>)
+  <li class=bug>
+    Servlet containers may refuse to let us set <a href="https://www.owasp.org/index.php/SecureFlag">secure cookie flag</a>.
+    Deal with it gracefully.
+    (<a href="https://issues.jenkins-ci.org/browse/JENKINS-25019">issue 25019</a>)
 </ul>
 </div><!--=TRUNK-END=-->
 
 <!-- these changes are controlled by the release process. DO NOT MODIFY -->
 <div id="rc" style="display:none;"><!--=BEGIN=-->
diff --git a/core/src/main/java/hudson/WebAppMain.java b/core/src/main/java/hudson/WebAppMain.java
index 1f332e9751..11d438d5ab 100644
--- a/core/src/main/java/hudson/WebAppMain.java
+++ b/core/src/main/java/hudson/WebAppMain.java
@@ -54,10 +54,11 @@ import javax.servlet.ServletResponse;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.TransformerFactoryConfigurationError;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.Date;
 import java.util.Locale;
 import java.util.logging.Level;
@@ -114,10 +115,12 @@ public class WebAppMain implements ServletContextListener {
                 // ignore this error.
             }
 
             installLogger();
 
+            markCookieAsHttpOnly(context);
+
             final FileAndDescription describedHomeDir = getHomeDir(event);
             home = describedHomeDir.file.getAbsoluteFile();
             home.mkdirs();
             System.out.println("Jenkins home directory: "+home+" found at: "+describedHomeDir.description);
 
@@ -249,10 +252,35 @@ public class WebAppMain implements ServletContextListener {
             LOGGER.log(SEVERE, "Failed to initialize Jenkins",e);
             throw e;
         }
     }
 
+    /**
+     * Set the session cookie as HTTP only.
+     *
+     * @see <a href="https://www.owasp.org/index.php/HttpOnly">discussion of this topic in OWASP</a>
+     */
+    private void markCookieAsHttpOnly(ServletContext context) {
+        try {
+            Method m;
+            try {
+                m = context.getClass().getMethod("getSessionCookieConfig");
+            } catch (NoSuchMethodException x) { // 3.0+
+                LOGGER.log(Level.FINE, "Failed to set secure cookie flag", x);
+                return;
+            }
+            Object sessionCookieConfig = m.invoke(context);
+
+            // not exposing session cookie to JavaScript to mitigate damage caused by XSS
+            Class scc = Class.forName("javax.servlet.SessionCookieConfig");
+            Method setHttpOnly = scc.getMethod("setHttpOnly",boolean.class);
+            setHttpOnly.invoke(sessionCookieConfig,true);
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, "Failed to set HTTP-only cookie flag", e);
+        }
+    }
+
     public void joinInit() throws InterruptedException {
         initThread.join();
     }
 
     /**
diff --git a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
index 6836467217..c10e51d526 100644
--- a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
+++ b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
@@ -12,10 +12,11 @@ import org.kohsuke.stapler.StaplerRequest;
 import javax.mail.internet.AddressException;
 import javax.mail.internet.InternetAddress;
 import javax.servlet.ServletContext;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import static hudson.Util.fixNull;
@@ -115,18 +116,21 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration {
                 LOGGER.log(Level.FINE, "Failed to set secure cookie flag", x);
                 return;
             }
             Object sessionCookieConfig = m.invoke(context);
 
-            // not exposing session cookie to JavaScript to mitigate damage caused by XSS
             Class scc = Class.forName("javax.servlet.SessionCookieConfig");
-            Method setHttpOnly = scc.getMethod("setHttpOnly",boolean.class);
-            setHttpOnly.invoke(sessionCookieConfig,true);
-
-            Method setSecure = scc.getMethod("setSecure",boolean.class);
+            Method setSecure = scc.getMethod("setSecure", boolean.class);
             boolean v = fixNull(jenkinsUrl).startsWith("https");
-            setSecure.invoke(sessionCookieConfig,v);
+            setSecure.invoke(sessionCookieConfig, v);
+        } catch (InvocationTargetException e) {
+            if (e.getTargetException() instanceof IllegalStateException) {
+                // servlet 3.0 spec seems to prohibit this from getting set at runtime,
+                // though Winstone is happy to accept i. see JENKINS-25019
+                return;
+            }
+            LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
         } catch (Exception e) {
             LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
         }
     }
 

Vulnerable code:             // not exposing session cookie to JavaScript to mitigate damage caused by XSS
            Method setHttpOnly = scc.getMethod("setHttpOnly",boolean.class);
            setHttpOnly.invoke(sessionCookieConfig,true);

            Method setSecure = scc.getMethod("setSecure",boolean.class);
            setSecure.invoke(sessionCookieConfig,v);
Fixed code:   <li class=bug>
    Servlet containers may refuse to let us set <a href="https://www.owasp.org/index.php/SecureFlag">secure cookie flag</a>.
    Deal with it gracefully.
    (<a href="https://issues.jenkins-ci.org/browse/JENKINS-25019">issue 25019</a>)
import java.lang.reflect.Method;
            markCookieAsHttpOnly(context);

    /**
     * Set the session cookie as HTTP only.
     *
     * @see <a href="https://www.owasp.org/index.php/HttpOnly">discussion of this topic in OWASP</a>
     */
    private void markCookieAsHttpOnly(ServletContext context) {
        try {
            Method m;
            try {
                m = context.getClass().getMethod("getSessionCookieConfig");
            } catch (NoSuchMethodException x) { // 3.0+
                LOGGER.log(Level.FINE, "Failed to set secure cookie flag", x);
                return;
            }
            Object sessionCookieConfig = m.invoke(context);

            // not exposing session cookie to JavaScript to mitigate damage caused by XSS
            Class scc = Class.forName("javax.servlet.SessionCookieConfig");
            Method setHttpOnly = scc.getMethod("setHttpOnly",boolean.class);
            setHttpOnly.invoke(sessionCookieConfig,true);
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "Failed to set HTTP-only cookie flag", e);
        }
    }

import java.lang.reflect.InvocationTargetException;
            Method setSecure = scc.getMethod("setSecure", boolean.class);
            setSecure.invoke(sessionCookieConfig, v);
        } catch (InvocationTargetException e) {
            if (e.getTargetException() instanceof IllegalStateException) {
                // servlet 3.0 spec seems to prohibit this from getting set at runtime,
                // though Winstone is happy to accept i. see JENKINS-25019
                return;
            }
            LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);