Skip to content

Commit

Permalink
[SECURITY-3245]
Browse files Browse the repository at this point in the history
  • Loading branch information
yaroslavafenkin authored and jenkinsci-cert-ci committed Sep 6, 2023
1 parent b8ac8cd commit 4bf6488
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
3 changes: 2 additions & 1 deletion core/src/main/java/hudson/console/ExpandableDetailsNote.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.Functions;
import hudson.MarkupText;
import java.io.IOException;
import java.util.logging.Level;
Expand All @@ -52,7 +53,7 @@ public ExpandableDetailsNote(String caption, String html) {
@Override
public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) {
text.addMarkup(charPos,
"<input type=button value='" + caption + "' class='reveal-expandable-detail'><div class='expandable-detail'>" + html + "</div>");
"<input type=button value='" + Functions.htmlAttributeEscape(caption) + "' class='reveal-expandable-detail'><div class='expandable-detail'>" + html + "</div>");
return null;
}

Expand Down
68 changes: 68 additions & 0 deletions test/src/test/java/jenkins/security/Security3245Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package jenkins.security;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Launcher;
import hudson.console.ExpandableDetailsNote;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.Builder;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import jenkins.tasks.SimpleBuildStep;
import org.htmlunit.html.HtmlPage;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

public class Security3245Test {

@Rule
public JenkinsRule j = new JenkinsRule();

@Issue("SECURITY-3245")
@Test
public void captionCannotAttributeEscape() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("p");
p.getBuildersList().add(new ExpandableDetailsNoteTestAction("' onclick=alert(1) foo='bar", "<h1></h1>"));
FreeStyleBuild build = j.buildAndAssertSuccess(p);

AtomicBoolean alerts = new AtomicBoolean();
try (JenkinsRule.WebClient wc = j.createWebClient()) {
wc.setAlertHandler((pr, s) -> alerts.set(true));
final HtmlPage page = wc.goTo(build.getUrl() + "console");
String content = page.getWebResponse().getContentAsString();
assertThat(content, containsString("<input type=button value='&#39; onclick=alert(1) foo=&#39;bar' class='reveal-expandable-detail'>"));

// Execute JavaScript code to simulate click event
String jsCode = "document.querySelector('.reveal-expandable-detail').dispatchEvent(new MouseEvent('click'));";
page.executeJavaScript(jsCode);

Assert.assertFalse("Alert not expected", alerts.get());
}
}

static class ExpandableDetailsNoteTestAction extends Builder implements SimpleBuildStep {

final String caption;
final String html;

ExpandableDetailsNoteTestAction(String caption, String html) {
this.caption = caption;
this.html = html;
}

@Override
public void perform(@NonNull Run<?, ?> run, @NonNull FilePath workspace, @NonNull EnvVars env, @NonNull Launcher launcher, @NonNull TaskListener listener) throws IOException {
listener.annotate(new ExpandableDetailsNote(caption, html));
}
}
}

0 comments on commit 4bf6488

Please sign in to comment.