Skip to content

fix XSS vulnerability in scaladoc search by escaping the input parameter#8018

Merged
lrytz merged 3 commits intoscala:2.12.xfrom
mpollmeier:scaladoc-rss-fix
May 3, 2019
Merged

fix XSS vulnerability in scaladoc search by escaping the input parameter#8018
lrytz merged 3 commits intoscala:2.12.xfrom
mpollmeier:scaladoc-rss-fix

Conversation

@mpollmeier
Copy link
Contributor

@mpollmeier mpollmeier commented May 2, 2019

Fixes scala/bug#11513

To trigger the XSS vulnerability, simply paste this into the search bar, e.g. on https://www.scala-lang.org/api/2.12.8/:

"\><img/src='1'onerror=alert(777111)>{{7*7}}

All credit for finding the vulnerability goes to Yeasir Arafat:
skylinearafat@gmail.com
https://www.facebook.com/skylinearafat.arafat

n.b. I've targeted 2.12.x because according to https://github.com/scala/scala/blob/2.13.x/CONTRIBUTING.md this will be merged into 2.13.x 'in time'.

to trigger XSS vuln, simply paste this into the search bar:
```
"\><img/src='1'onerror=alert(777111)>{{7*7}}
```

all credit for finding the vulnerability goes to *Yeasir Arafat* <skylinearafat@gmail.com>
@scala-jenkins scala-jenkins added this to the 2.12.9 milestone May 2, 2019
@hrhino
Copy link
Contributor

hrhino commented May 2, 2019

I think they mean "in due time", not "in time for" anything particular.

This isn't really XSS, is it? If you paste some sketchy code into your own browser, that's on you. If there were a way to get a specific scaladoc page to then serve that to other people, that would be a problem.

It's better to escape now, though, while we still can. 👍

Expanding: this shows a (potential) bug in scaladoc: you cannot cause the xss with a direct link:

https://www.scala-lang.org/api/2.12.8/?search=%22/%3E%3Cimg/src=%271%27onerror=alert(777111)%3E%7B%7B7*7%7D%7D

never manages to inject that code. Has it been long enough that we can use the history API rather than sticking the search string into the URL?

@mpollmeier
Copy link
Contributor Author

If you paste some sketchy code into your own browser, that's on you.

This is not about the input field in the html, but about how the input parameter is handled. An attacker could send the victim a link like https://example.com/api/?search=%22\%3E%3Cimg/src=%271%27onerror=alert(777111)%3E{{7*7}} where the payload instructs the browser to extract userdata for that particular domain (example.com). This is not really critical for https://www.scala-lang.org/api, but for users who host their api docs under their company url.

@hrhino
Copy link
Contributor

hrhino commented May 2, 2019

Sorry, I edited instead of posting a new comment. I'm not arguing against this change; I'm simply pointing out that it doesn't appear to be an actual vulnerability affecting scaladoc sites out there right now, unless there's a different attack vector I hadn't thought of.

@hrhino
Copy link
Contributor

hrhino commented May 2, 2019

Also, I hate to be a nitpicker, but now I can't search for :+.

@hrhino
Copy link
Contributor

hrhino commented May 2, 2019

And to prove I'm not just a naysayer, may I suggest:

diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js
index e899f06b5c..84004ef468 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js
@@ -532,7 +532,6 @@ function searchAll() {
     scheduler.clear("search"); // clear previous search
     maxJobs = 1; // clear previous max
     var searchStr = $("#textfilter input").attr("value").trim() || '';
-    searchStr = escape(searchStr);
 
     if (searchStr === '') {
         $("div#search-results").hide();
@@ -562,10 +561,11 @@ function searchAll() {
     entityH1.innerHTML = "Entity results";
     entityResults.appendChild(entityH1);
 
-    $("div#results-content")
-        .prepend("<span class='search-text'>"
-                +"  Showing results for <span class='query-str'>\"" + searchStr + "\"</span>"
-                +"</span>");
+    var searchTextEl = $("<span class='search-text'>"
+                        +"  Showing results for <span class='query-str' />"
+                        +"</span>");
+    searchTextEl.find(".query-str").text(searchStr);
+    $("div#results-content").prepend(searchTextEl);

@NthPortal
Copy link
Contributor

NthPortal commented May 2, 2019

I would personally be inclined to never create the tag with any contents using jQuery (or anything else, for that matter) - always setting the text outside of the tag means you will never be able to accidentally open yourself up to injection.

In this case I would do one of the following (even though it's slightly more verbose):

$("div#results-content")
    .prepend(
        $("<span>", {class: "search-text"})
            .append(document.createTextNode("  Showing results for "))
            .append($("<span>", {class: "query-str", text: searchStr}))
    );
$("div#results-content")
    .prepend(
        $("<span>")
            .addClass("search-text")
            .append(document.createTextNode("  Showing results for "))
            .append($("<span>").addClass("query-str").text(searchStr))
    );

@NthPortal NthPortal added the tool:scaladoc Changes to Scaladoc, the API documentation generator label May 2, 2019
scheduler.clear("search"); // clear previous search
maxJobs = 1; // clear previous max
var searchStr = $("#textfilter input").attr("value").trim() || '';
searchStr = escape(searchStr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the correct solution regardless - as pointed about by Harrison, it prevents you from searching for some things (like :+). The problem is that the untrusted string is embedded in a tag creation below.

@jdelta-RBS
Copy link

@mpollmeier I tried this in Chrome, FireFox, IE -> nothing. It does work as originally posted, but it is not a realistic attack vector that would warrant any type of change.

rather than escaping the search string, which breaks the search for
e.g. `:+`

solution contributed by NthPortal in scala#8018 (comment)
@mpollmeier
Copy link
Contributor Author

Thanks for all the feedback! I updated the PR to use @NthPortal's 2nd solution from #8018 (comment), which IMO is the cleanest approach.

Copy link
Contributor

@hrhino hrhino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Published the doc site locally; all appears well. I can search for my silly symbolic aliases, and I can't give myself popups, so LGTM.

Thanks!

$("<span>")
.addClass("search-text")
.append(document.createTextNode(" Showing results for "))
.append($("<span>").addClass("query-str").text(searchStr))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's how it's done. Mine felt like a hack, but it's been so long since I've used jQuery (Ext.js for life!) that I forgot the right way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I heavily abused google and the browser console to figure it out

@lrytz
Copy link
Member

lrytz commented May 3, 2019

Thanks, everyone involved!

@lrytz lrytz merged commit 2dbf5c1 into scala:2.12.x May 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tool:scaladoc Changes to Scaladoc, the API documentation generator

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants