SECURITY: Onebox templates' HTML injections (stable).

The use of triple-curlies on Mustache templates opens the possibility for HTML injections.
This commit is contained in:
Roman Rizzi 2023-11-09 13:47:23 +11:00 committed by Krzysztof Kotlarek
parent 24cca10da7
commit 628b293ff5
5 changed files with 104 additions and 7 deletions

View File

@ -36,7 +36,7 @@ module Onebox
body, excerpt = compute_body(raw["body"]) body, excerpt = compute_body(raw["body"])
ulink = URI(link) ulink = URI(link)
labels = raw["labels"].map { |l| { name: Emoji.codes_to_img(l["name"]) } } labels = raw["labels"].map { |l| { name: Emoji.codes_to_img(CGI.escapeHTML(l["name"])) } }
{ {
link: @url, link: @url,

View File

@ -6,15 +6,15 @@
<h3> <h3>
<a class="badge-wrapper bullet" href="{{url}}"> <a class="badge-wrapper bullet" href="{{url}}">
{{#color}} {{#color}}
<span class="badge-category-bg" style="background-color: #{{{color}}}"></span> <span class="badge-category-bg" style="background-color: #{{color}}"></span>
{{/color}} {{/color}}
<span class="clear-badge"><span>{{{name}}}</span></span> <span class="clear-badge"><span>{{name}}</span></span>
</a> </a>
</h3> </h3>
{{#description}} {{#description}}
<div> <div>
<span class="description"> <span class="description">
<p>{{{description}}}</p> <p>{{description}}</p>
</span> </span>
</div> </div>
{{/description}} {{/description}}
@ -23,8 +23,8 @@
{{#subcategories}} {{#subcategories}}
<span class="subcategory"> <span class="subcategory">
<a class="badge-wrapper bullet" href="{{url}}"> <a class="badge-wrapper bullet" href="{{url}}">
<span class="badge-category-bg" style="background-color: #{{{color}}}"></span> <span class="badge-category-bg" style="background-color: #{{color}}"></span>
<span class="badge-category clear-badge"><span class="category-name">{{{name}}}</span></span> <span class="badge-category clear-badge"><span class="category-name">{{name}}</span></span>
</a> </a>
</span> </span>
{{/subcategories}} {{/subcategories}}

View File

@ -8,7 +8,7 @@
<svg class="fa d-icon d-icon-d-chat svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#d-chat"></use></svg> <svg class="fa d-icon d-icon-d-chat svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#d-chat"></use></svg>
</span> </span>
{{/is_category}} {{/is_category}}
<span class="clear-badge">{{{channel_name}}}</span> <span class="clear-badge">{{channel_name}}</span>
</a> </a>
</h3> </h3>
{{#description}} {{#description}}

View File

@ -0,0 +1,73 @@
{
"url": "https://api.github.com/repos/romanrizzi/avalancha-parser/issues/2",
"repository_url": "https://api.github.com/repos/romanrizzi/avalancha-parser",
"labels_url": "https://api.github.com/repos/romanrizzi/avalancha-parser/issues/2/labels{/name}",
"comments_url": "https://api.github.com/repos/romanrizzi/avalancha-parser/issues/2/comments",
"events_url": "https://api.github.com/repos/romanrizzi/avalancha-parser/issues/2/events",
"html_url": "https://github.com/romanrizzi/avalancha-parser/issues/2",
"id": 1957276127,
"node_id": "I_kwDOEdKQe850qanf",
"number": 2,
"title": "Test issue #2",
"user": {
"login": "romanrizzi",
"id": 5025816,
"node_id": "MDQ6VXNlcjUwMjU4MTY=",
"avatar_url": "https://avatars.githubusercontent.com/u/5025816?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/romanrizzi",
"html_url": "https://github.com/romanrizzi",
"followers_url": "https://api.github.com/users/romanrizzi/followers",
"following_url": "https://api.github.com/users/romanrizzi/following{/other_user}",
"gists_url": "https://api.github.com/users/romanrizzi/gists{/gist_id}",
"starred_url": "https://api.github.com/users/romanrizzi/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/romanrizzi/subscriptions",
"organizations_url": "https://api.github.com/users/romanrizzi/orgs",
"repos_url": "https://api.github.com/users/romanrizzi/repos",
"events_url": "https://api.github.com/users/romanrizzi/events{/privacy}",
"received_events_url": "https://api.github.com/users/romanrizzi/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"id": 6119137046,
"node_id": "LA_kwDOEdKQe88AAAABbLqfFg",
"url": "https://api.github.com/repos/romanrizzi/avalancha-parser/labels/Test%20:+1:%20%3Cstyle%3Ebody%20%7Bdisplay:%20none%7D%3C/style%3E",
"name": "Test :+1: <style>body {display: none}</style>",
"color": "0E8A16",
"default": false,
"description": ""
}
],
"state": "open",
"locked": false,
"assignee": null,
"assignees": [
],
"milestone": null,
"comments": 0,
"created_at": "2023-10-23T14:13:07Z",
"updated_at": "2023-10-23T14:13:07Z",
"closed_at": null,
"author_association": "OWNER",
"active_lock_reason": null,
"body": "test",
"closed_by": null,
"reactions": {
"url": "https://api.github.com/repos/romanrizzi/avalancha-parser/issues/2/reactions",
"total_count": 0,
"+1": 0,
"-1": 0,
"laugh": 0,
"hooray": 0,
"confused": 0,
"heart": 0,
"rocket": 0,
"eyes": 0
},
"timeline_url": "https://api.github.com/repos/romanrizzi/avalancha-parser/issues/2/timeline",
"performed_via_github_app": null,
"state_reason": null
}

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
RSpec.describe Onebox::Engine::GithubIssueOnebox do
before do
@link = "https://github.com/discourse/discourse/issues/1"
stub_request(:get, "https://api.github.com/repos/discourse/discourse/issues/1").to_return(
status: 200,
body: onebox_response("github_issue_onebox"),
)
end
include_context "with engines"
it_behaves_like "an engine"
describe "#to_html" do
it "sanitizes the input and transform the emoji into an img tag" do
sanitized_label =
'Test <img src="/images/emoji/twitter/+1.png?v=12" title="+1" class="emoji" alt="+1" loading="lazy" width="20" height="20"> &lt;style&gt;body {display: none}&lt;/style&gt;'
expect(html).to include(sanitized_label)
end
end
end