Security context
MediumGHSA-7fpg-pp3m-h22f CVE-2014-2058Published May 17, 2022

Jenkins allows attackers to execute arbitrary jobs

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

1.533 → fixed in 1.5510 → fixed in 1.532.2

Details

BuildTrigger in Jenkins before 1.551 and LTS before 1.532.2 allows remote authenticated users to bypass access restrictions and execute arbitrary jobs by configuring a job to trigger another job. NOTE: this vulnerability exists because of an incomplete fix for CVE-2013-7330.

The fix

[FIXED SECURITY-109] SECURITY-55 fix to BuildTrigger

Jesse Glick· Feb 11, 2014, 12:13 AM+521b6b2a367a7
core/src/main/java/hudson/model/AbstractProject.java+8 1
@@ -1939,7 +1939,14 @@ protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
for (Publisher _t : Descriptor.newInstancesFromHeteroList(req, json, "publisher", Jenkins.getInstance().getExtensionList(BuildTrigger.DescriptorImpl.class))) {
BuildTrigger t = (BuildTrigger) _t;
- for (AbstractProject downstream : t.getChildProjects(this)) {
+ List<AbstractProject> childProjects;
+ SecurityContext orig = ACL.impersonate(ACL.SYSTEM);
+ try {
+ childProjects = t.getChildProjects(this);
+ } finally {
+ SecurityContextHolder.setContext(orig);
+ }
+ for (AbstractProject downstream : childProjects) {
downstream.checkPermission(BUILD);
}
}
test/src/test/java/hudson/tasks/BuildTriggerTest.java+44 0
@@ -23,14 +23,26 @@
*/
package hudson.tasks;
+import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import hudson.maven.MavenModuleSet;
import hudson.maven.MavenModuleSetBuild;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
+import hudson.model.Item;
import hudson.model.Result;
import hudson.model.Run;
+import hudson.security.AuthorizationMatrixProperty;
+import hudson.security.LegacySecurityRealm;
+import hudson.security.Permission;
+import hudson.security.ProjectMatrixAuthorizationStrategy;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import jenkins.model.Jenkins;
import org.jvnet.hudson.test.ExtractResourceSCM;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.MockBuilder;
@@ -131,4 +143,36 @@ public void testMavenBuildTrigger() throws Exception {
public void testMavenTriggerEvenWhenUnstable() throws Exception {
doMavenTriggerTest(true);
}
+
+ public void testConfigureDownstreamProjectSecurity() throws Exception {
+ jenkins.setSecurityRealm(new LegacySecurityRealm());
+ ProjectMatrixAuthorizationStrategy auth = new ProjectMatrixAuthorizationStrategy();
+ auth.add(Jenkins.READ, "alice");
+ jenkins.setAuthorizationStrategy(auth);
+ FreeStyleProject upstream = createFreeStyleProject("upstream");
+ Map<Permission,Set<String>> perms = new HashMap<Permission,Set<String>>();
+ perms.put(Item.READ, Collections.singleton("alice"));
+ perms.put(Item.CONFIGURE, Collections.singleton("alice"));
+ upstream.addProperty(new AuthorizationMatrixProperty(perms));
+ FreeStyleProject downstream = createFreeStyleProject("downstream");
+ /* Original SECURITY-55 test case:
+ downstream.addProperty(new AuthorizationMatrixProperty(Collections.singletonMap(Item.READ, Collections.singleton("alice"))));
+ */
+ WebClient wc = createWebClient();
+ wc.login("alice");
+ HtmlPage page = wc.getPage(upstream, "configure");
+ HtmlForm config = page.getFormByName("config");
+ config.getButtonByCaption("Add post-build action").click(); // lib/hudson/project/config-publishers2.jelly
+ page.getAnchorByText("Build other projects").click();
+ HtmlTextInput childProjects = config.getInputByName("buildTrigger.childProjects");
+ childProjects.setValueAttribute("downstream");
+ try {
+ submit(config);
+ fail();
+ } catch (FailingHttpStatusCodeException x) {
+ assertEquals(403, x.getStatusCode());
+ }
+ assertEquals(Collections.emptyList(), upstream.getDownstreamProjects());
+ }
+
}

References