summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/issue.js6
-rw-r--r--app/views/shared/issuable/_close_reopen_report_toggle.html.haml2
-rw-r--r--changelogs/unreleased/security-fix-mermaid-issue.yml5
-rw-r--r--spec/frontend/fixtures/static/issue_with_mermaid_graph.html82
-rw-r--r--spec/frontend/issue_spec.js27
5 files changed, 120 insertions, 2 deletions
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index f0967e77faf..29bb6eff1b2 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -108,7 +108,11 @@ export default class Issue {
} else {
this.disableCloseReopenButton($button);
- const url = $button.attr('href');
+ const url = $button.data('close-reopen-url');
+ if (!url) {
+ return;
+ }
+
return axios
.put(url)
.then(({ data }) => {
diff --git a/app/views/shared/issuable/_close_reopen_report_toggle.html.haml b/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
index 9d718083d2d..8575a61aae8 100644
--- a/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
+++ b/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
@@ -11,7 +11,7 @@
.float-left.btn-group.prepend-left-10.issuable-close-dropdown.droplab-dropdown.js-issuable-close-dropdown
= link_to "#{display_button_action} #{display_issuable_type}", close_reopen_issuable_path(issuable),
- method: button_method, class: "#{button_class} btn-#{button_action} #{(add_blocked_class ? 'btn-issue-blocked' : '')}", title: "#{display_button_action} #{display_issuable_type}", data: { qa_selector: 'close_issue_button' }
+ method: button_method, class: "#{button_class} btn-#{button_action} #{(add_blocked_class ? 'btn-issue-blocked' : '')}", title: "#{display_button_action} #{display_issuable_type}", data: { qa_selector: 'close_issue_button', 'close-reopen-url': close_reopen_issuable_path(issuable) }
= button_tag type: 'button', class: "#{toggle_class} btn-#{button_action}-color",
data: { 'dropdown-trigger' => '#issuable-close-menu' }, 'aria-label' => _('Toggle dropdown') do
diff --git a/changelogs/unreleased/security-fix-mermaid-issue.yml b/changelogs/unreleased/security-fix-mermaid-issue.yml
new file mode 100644
index 00000000000..4c254f8a4f5
--- /dev/null
+++ b/changelogs/unreleased/security-fix-mermaid-issue.yml
@@ -0,0 +1,5 @@
+---
+title: Disallow user to control PUT request using mermaid markdown in issue description
+merge_request:
+author:
+type: security
diff --git a/spec/frontend/fixtures/static/issue_with_mermaid_graph.html b/spec/frontend/fixtures/static/issue_with_mermaid_graph.html
new file mode 100644
index 00000000000..4b60842a655
--- /dev/null
+++ b/spec/frontend/fixtures/static/issue_with_mermaid_graph.html
@@ -0,0 +1,82 @@
+<div class="description" updated-at="">
+ <div class="md issue-realtime-trigger-pulse">
+ <svg
+ id="mermaid-1587752414912"
+ width="100%"
+ xmlns="http://www.w3.org/2000/svg"
+ style="max-width: 185.35000610351562px;"
+ viewBox="0 0 185.35000610351562 50.5"
+ class="mermaid"
+ >
+ <g transform="translate(0, 0)">
+ <g class="output">
+ <g class="clusters"></g>
+ <g class="edgePaths"></g>
+ <g class="edgeLabels"></g>
+ <g class="nodes">
+ <g
+ class="node js-issuable-actions btn-close clickable"
+ style="opacity: 1;"
+ id="A"
+ transform="translate(92.67500305175781,25.25)"
+ title="click to PUT"
+ >
+ <a
+ class="js-issuable-actions btn-close clickable"
+ href="https://invalid"
+ rel="noopener"
+ >
+ <rect
+ rx="0"
+ ry="0"
+ x="-84.67500305175781"
+ y="-17.25"
+ width="169.35000610351562"
+ height="34.5"
+ class="label-container"
+ ></rect>
+ <g class="label" transform="translate(0,0)">
+ <g transform="translate(-74.67500305175781,-7.25)">
+ <text style="">
+ <tspan xml:space="preserve" dy="1em" x="1">Click to send a PUT request</tspan>
+ </text>
+ </g>
+ </g>
+ </a>
+ </g>
+ </g>
+ </g>
+ </g>
+ <text class="source" display="none">
+ Click to send a PUT request
+ </text>
+ </svg>
+ </div>
+ <textarea
+ data-update-url="/h5bp/html5-boilerplate/-/issues/35.json"
+ dir="auto"
+ class="hidden js-task-list-field"
+ ></textarea>
+ <div class="modal-open recaptcha-modal js-recaptcha-modal" style="display: none;">
+ <div role="dialog" tabindex="-1" class="modal d-block">
+ <div role="document" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title float-left">Please solve the reCAPTCHA</h4>
+ <button type="button" data-dismiss="modal" aria-label="Close" class="close float-right">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div>
+ <p>We want to be sure it is you, please confirm you are not a robot.</p>
+ <div></div>
+ </div>
+ </div>
+ <!---->
+ </div>
+ </div>
+ </div>
+ <div class="modal-backdrop fade show"></div>
+ </div>
+</div>
diff --git a/spec/frontend/issue_spec.js b/spec/frontend/issue_spec.js
index 586bd7f8529..24020daf728 100644
--- a/spec/frontend/issue_spec.js
+++ b/spec/frontend/issue_spec.js
@@ -18,6 +18,7 @@ describe('Issue', () => {
preloadFixtures('issues/closed-issue.html');
preloadFixtures('issues/issue-with-task-list.html');
preloadFixtures('issues/open-issue.html');
+ preloadFixtures('static/issue_with_mermaid_graph.html');
function expectErrorMessage() {
const $flashMessage = $('div.flash-alert');
@@ -228,4 +229,30 @@ describe('Issue', () => {
});
});
});
+
+ describe('when not displaying blocked warning', () => {
+ describe('when clicking a mermaid graph inside an issue description', () => {
+ let mock;
+ let spy;
+
+ beforeEach(() => {
+ loadFixtures('static/issue_with_mermaid_graph.html');
+ mock = new MockAdapter(axios);
+ spy = jest.spyOn(axios, 'put');
+ });
+
+ afterEach(() => {
+ mock.restore();
+ jest.clearAllMocks();
+ });
+
+ it('does not make a PUT request', () => {
+ Issue.prototype.initIssueBtnEventListeners();
+
+ $('svg a.js-issuable-actions').trigger('click');
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+ });
+ });
});