diff --git a/core/src/main/resources/lib/form/helpLink.jelly b/core/src/main/resources/lib/form/helpLink.jelly index 0c1ab38aa7eb..dcf279ed6585 100644 --- a/core/src/main/resources/lib/form/helpLink.jelly +++ b/core/src/main/resources/lib/form/helpLink.jelly @@ -53,7 +53,7 @@ THE SOFTWARE. - + ? diff --git a/test/src/test/java/jenkins/security/Security2779Test.java b/test/src/test/java/jenkins/security/Security2779Test.java new file mode 100644 index 000000000000..a26d2c809cff --- /dev/null +++ b/test/src/test/java/jenkins/security/Security2779Test.java @@ -0,0 +1,84 @@ +package jenkins.security; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.gargoylesoftware.htmlunit.AlertHandler; +import com.gargoylesoftware.htmlunit.ScriptResult; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import hudson.model.UnprotectedRootAction; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestExtension; + +@RunWith(Parameterized.class) +public class Security2779Test { + public static final String URL_NAME = "security2779"; + private final String selector; + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Parameterized.Parameters + public static Collection getSelectors() { + return Arrays.asList("#link-panel a", "#icon-panel svg"); + } + + public Security2779Test(String selector) { + this.selector = selector; + } + + @Test + public void noXssInHelp() throws Exception { + final AtomicInteger alerts = new AtomicInteger(); + final JenkinsRule.WebClient webClient = j.createWebClient(); + webClient.setAlertHandler((AlertHandler) (p, s) -> alerts.addAndGet(1)); + final HtmlPage page = webClient.goTo(URL_NAME); + final ScriptResult eventScript = page.executeJavaScript("document.querySelector('" + selector + "').dispatchEvent(new Event('mouseover'))"); + final Object eventResult = eventScript.getJavaScriptResult(); + assertThat(eventResult, instanceOf(boolean.class)); + Assert.assertTrue((boolean) eventResult); + webClient.waitForBackgroundJavaScript(2000); + Assert.assertEquals(0, alerts.get()); + + final ScriptResult innerHtmlScript = page.executeJavaScript("document.querySelector('#tt').innerHTML"); + Object jsResult = innerHtmlScript.getJavaScriptResult(); + assertThat(jsResult, instanceOf(String.class)); + String jsResultString = (String) jsResult; + + // assert leading space to identify unintentional double-escaping (<) as test failure + assertThat("tooltip does not contain dangerous HTML", jsResultString, not(containsString(" "; + } + } +} diff --git a/test/src/test/resources/jenkins/security/Security2779Test/ViewHolder/index.jelly b/test/src/test/resources/jenkins/security/Security2779Test/ViewHolder/index.jelly new file mode 100644 index 000000000000..3cd5e2e3d4b5 --- /dev/null +++ b/test/src/test/resources/jenkins/security/Security2779Test/ViewHolder/index.jelly @@ -0,0 +1,13 @@ + + + + + +
+ +
+
+
+