Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate 2023-02-15 security fix for SECURITY-3032 into default branch #491

Merged
merged 4 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/main/resources/lib/hudson/test/failed-test.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ THE SOFTWARE.
}
</style>
</st:once>
<j:set var="id" value="${h.jsStringEscape(url)}"/>
<j:set var="open" value="showFailureSummary('test-${id}','${url}/summary')"/>
<j:set var="close" value="hideFailureSummary('test-${id}')"/>
<j:set var="id" value="${h.htmlAttributeEscape(url)}"/>
<j:set var="idjs" value="${h.jsStringEscape(url)}"/>
<j:set var="open" value="showFailureSummary('test-${h.jsStringEscape(id)}','${idjs}/summary')"/>
<j:set var="close" value="hideFailureSummary('test-${h.jsStringEscape(id)}')"/>
<a id="test-${id}-showlink" onclick="${open}" title="${%Show details}">
<l:icon src="symbol-add-outline plugin-ionicons-api" class="icon-sm"/>
</a>
Expand Down
58 changes: 58 additions & 0 deletions src/test/java/hudson/tasks/junit/CaseResultTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,38 @@
*/
package hudson.tasks.junit;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsEmptyCollection.empty;

import hudson.FilePath;
import hudson.Functions;
import hudson.model.FreeStyleProject;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.model.FreeStyleBuild;
import hudson.Launcher;
import hudson.tasks.Shell;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Email;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.TestBuilder;
import com.gargoylesoftware.htmlunit.AlertHandler;
import com.gargoylesoftware.htmlunit.html.HtmlImage;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.xml.XmlPage;
import org.jvnet.hudson.test.TouchBuilder;
import org.junit.Assume;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
Expand Down Expand Up @@ -105,6 +117,52 @@ public void testIssue20090516() throws Exception {
"http://localhost:8080/stuff/");
}

/**
* Verifies that malicious code is escaped when expanding a failed test on the summary page
*/
@Test
public void noPopUpsWhenExpandingATest() throws Exception {
Assume.assumeFalse(Functions.isWindows());

FreeStyleProject project = rule.createFreeStyleProject("escape_test");

//Shell command which includes a vulnerability
Shell shell = new Shell("echo \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" ?><testsuite "
+ "errors=\\\"1\\\" failures=\\\"0\\\" hostname=\\\"whocares\\\" "
+ "name=\\\"nobody\\\" tests=\\\"1\\\" time=\\\"0.016\\\" "
+ "timestamp=\\\"2023-01-01T15:42:30\\\"><testcase classname=\\\"'+alert(1)+'\\\""
+ " name=\\\"testHudsonReporting\\\" time=\\\"0.016\\\"><error type=\\\"java"
+ ".lang.NullPointerException\\\">java.lang.NullPointerException&#13;"
+ "</error></testcase></testsuite>\" > junit.xml");

// Schedule a build of the project, passing in the shell command
project.getBuildersList().add(shell);
project.getPublishersList().add(new JUnitResultArchiver("*.xml"));
FreeStyleBuild build = project.scheduleBuild2(1).get();
rule.assertBuildStatus(Result.UNSTABLE, build);
TestResult testResult = build.getAction(TestResultAction.class).getResult();

// Mock an HTML page and create a new alerter to track if there are any popups
JenkinsRule.WebClient webClient = rule.createWebClient();
Alerter alerter = new Alerter();
webClient.setAlertHandler(alerter);
HtmlPage page = webClient.goTo("job/escape_test/1/testReport/");

//The Xpath here is for the '+' on the page, which when clicked expands the test
//the element we want to test is the first icon-sm in the list from the page
List<HtmlElement> elements = page.getByXPath("//*[@class='icon-sm']");
elements.get(0).click();
webClient.waitForBackgroundJavaScript(2000);
assertThat(alerter.messages, empty());
}

static class Alerter implements AlertHandler {
List<String> messages = Collections.synchronizedList(new ArrayList<>());
@Override
public void handleAlert(final Page page, final String message) {
messages.add(message);
}
}

/**
* Verifies that the error message and stacktrace from a failed junit test actually render properly.
Expand Down