Skip to content

Commit bfa9b30

Browse files
committed
[SECURITY-3205]
1 parent 6a89fd4 commit bfa9b30

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

src/main/java/org/jenkinsci/plugins/scriptler/ScriptlerManagement.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,12 @@ public HttpResponse doRemoveScript(StaplerRequest res, StaplerResponse rsp, @Que
332332
checkPermission(ScriptlerPermissions.CONFIGURE);
333333

334334
// remove the file
335-
File oldScript = new File(getScriptDirectory(), id);
335+
File scriptDirectory = getScriptDirectory();
336+
File oldScript = new File(scriptDirectory, id);
337+
if (!Util.isDescendant(scriptDirectory, oldScript)) {
338+
LOGGER.log(Level.WARNING, "Folder traversal detected, file path received: {0}, after fixing: {1}", new Object[]{id, oldScript});
339+
throw new Failure("Invalid file path received: " + id);
340+
}
336341
if(!oldScript.delete() && oldScript.exists()) {
337342
throw new Failure("not able to delete " + oldScript.getAbsolutePath());
338343
}

src/test/java/org/jenkinsci/plugins/scriptler/restapi/ScriptlerRestApiTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
import static org.junit.Assert.assertTrue;
55
import static org.junit.Assert.fail;
66

7+
import java.net.URL;
8+
import java.util.Collections;
9+
import org.htmlunit.HttpMethod;
10+
import org.htmlunit.WebRequest;
711
import org.htmlunit.html.*;
812
//import org.htmlunit.javascript.host.URL;
913
import hudson.ExtensionList;
@@ -18,9 +22,11 @@
1822
import java.util.List;
1923

2024
import org.apache.commons.fileupload.FileItem;
25+
import org.htmlunit.util.NameValuePair;
2126
import org.jenkinsci.plugins.scriptler.ScriptlerManagementHelper;
2227
import org.jenkinsci.plugins.scriptler.ScriptlerManagement;
2328
import org.jenkinsci.plugins.scriptler.config.Parameter;
29+
import org.jenkinsci.plugins.scriptler.config.ScriptlerConfiguration;
2430
import org.junit.*;
2531
import org.jvnet.hudson.test.BuildWatcher;
2632
import org.jvnet.hudson.test.Issue;
@@ -127,4 +133,29 @@ public void testUnknownScript() throws Exception {
127133
JenkinsRule.WebClient webClient = j.createWebClient();
128134
webClient.goTo("scriptler/runScript?id=unknown.groovy");
129135
}
136+
137+
@Test
138+
@Issue("SECURITY-3205")
139+
public void fixFolderTraversalThroughDeleteScript() throws Exception {
140+
File configurationFile = ScriptlerConfiguration.getXmlFile().getFile();
141+
String path = "../" + configurationFile.getName();
142+
143+
try (JenkinsRule.WebClient webClient = j.createWebClient()) {
144+
URL rootUrl = new URL(webClient.getContextPath() + "scriptler/removeScript");
145+
WebRequest req = new WebRequest(rootUrl, HttpMethod.POST);
146+
req.setRequestParameters(Collections.singletonList(new NameValuePair("id", path)));
147+
webClient.addCrumb(req);
148+
webClient.getPage(req);
149+
fail();
150+
} catch (FailingHttpStatusCodeException e) {
151+
if (e.getStatusCode() != 400) {
152+
// some other kind of error that we're not checking for
153+
throw e;
154+
}
155+
if (!configurationFile.exists()) {
156+
fail("The configuration file was deleted");
157+
}
158+
assert(e.getResponse().getContentAsString().contains("Invalid file path received: " + path));
159+
}
160+
}
130161
}

0 commit comments

Comments
 (0)