Prevent possible XSS when using jQuery (#18289)

In the case of misuse or misunderstanding from a developer whereby,
if `sel` can receive user-controlled data, jQuery `$(sel)` can lead to the
creation of a new element. Current usage is using hard-coded selectors
in the templates, but nobody prevents that from expanding to
user-controlled somehow.
This commit is contained in:
Gusted 2022-01-16 05:14:32 +00:00 committed by GitHub
parent 4b4884ce88
commit 661d3d28e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 39 additions and 34 deletions

View file

@ -127,3 +127,8 @@ We forbid `dataset` usage, its camel-casing behaviour makes it hard to grep for
### Vue2/Vue3 and JSX ### Vue2/Vue3 and JSX
Gitea is using Vue2 now, we plan to upgrade to Vue3. We decided not to introduce JSX to keep the HTML and the JavaScript code separated. Gitea is using Vue2 now, we plan to upgrade to Vue3. We decided not to introduce JSX to keep the HTML and the JavaScript code separated.
### jQuery's `$(...)`
jQuery's `$` function has a broad functionality depending on the input. Well, this can be seen as nice, it's also a fallpit for possible XSS attacks when the input is user-controlled.
The usage of the function can be correct in certain situations, but it is discourage and recommended to use a more specific function of jQuery(e.g. `$.find`, `$.parseHTML`).

View file

@ -2,7 +2,7 @@ import Vue from 'vue';
import {vueDelimiters} from './VueComponentLoader.js'; import {vueDelimiters} from './VueComponentLoader.js';
export function initRepoBranchTagDropdown(selector) { export function initRepoBranchTagDropdown(selector) {
$(selector).each(function () { $.find(selector).each(function () {
const $dropdown = $(this); const $dropdown = $(this);
const $data = $dropdown.find('.data'); const $data = $dropdown.find('.data');
const data = { const data = {

View file

@ -124,7 +124,7 @@ export function initGlobalCommon() {
$('.tabable.menu .item').tab(); $('.tabable.menu .item').tab();
$('.toggle.button').on('click', function () { $('.toggle.button').on('click', function () {
$($(this).data('target')).slideToggle(100); $.find($(this).data('target')).slideToggle(100);
}); });
// make table <tr> and <td> elements clickable like a link // make table <tr> and <td> elements clickable like a link
@ -202,7 +202,7 @@ export function initGlobalLinkActions() {
closable: false, closable: false,
onApprove() { onApprove() {
if ($this.data('type') === 'form') { if ($this.data('type') === 'form') {
$($this.data('form')).trigger('submit'); $.find($this.data('form')).trigger('submit');
return; return;
} }
@ -240,7 +240,7 @@ export function initGlobalLinkActions() {
closable: false, closable: false,
onApprove() { onApprove() {
if ($this.data('type') === 'form') { if ($this.data('type') === 'form') {
$($this.data('form')).trigger('submit'); $.find($this.data('form')).trigger('submit');
return; return;
} }
@ -293,7 +293,7 @@ export function initGlobalLinkActions() {
export function initGlobalButtons() { export function initGlobalButtons() {
$('.show-panel.button').on('click', function () { $('.show-panel.button').on('click', function () {
$($(this).data('panel')).show(); $.find($(this).data('panel')).show();
}); });
$('.hide-panel.button').on('click', function (event) { $('.hide-panel.button').on('click', function (event) {
@ -301,7 +301,7 @@ export function initGlobalButtons() {
event.preventDefault(); event.preventDefault();
let sel = $(this).attr('data-panel'); let sel = $(this).attr('data-panel');
if (sel) { if (sel) {
$(sel).hide(); $.find(sel).hide();
return; return;
} }
sel = $(this).attr('data-panel-closest'); sel = $(this).attr('data-panel-closest');
@ -314,8 +314,8 @@ export function initGlobalButtons() {
}); });
$('.show-modal.button').on('click', function () { $('.show-modal.button').on('click', function () {
$($(this).data('modal')).modal('show'); $.find($(this).data('modal')).modal('show');
const colorPickers = $($(this).data('modal')).find('.color-picker'); const colorPickers = $.find($(this).data('modal')).find('.color-picker');
if (colorPickers.length > 0) { if (colorPickers.length > 0) {
initCompColorPicker(); initCompColorPicker();
} }

View file

@ -1,7 +1,7 @@
import {initCompColorPicker} from './ColorPicker.js'; import {initCompColorPicker} from './ColorPicker.js';
export function initCompLabelEdit(selector) { export function initCompLabelEdit(selector) {
if (!$(selector).length) return; if (!$.find(selector).length) return;
// Create label // Create label
const $newLabelPanel = $('.new-label.segment'); const $newLabelPanel = $('.new-label.segment');
$('.new-label.button').on('click', () => { $('.new-label.button').on('click', () => {

View file

@ -2,6 +2,6 @@ export function initRepoBranchButton() {
$('.show-create-branch-modal.button').on('click', function () { $('.show-create-branch-modal.button').on('click', function () {
$('#create-branch-form')[0].action = $('#create-branch-form').data('base-action') + $(this).data('branch-from-urlcomponent'); $('#create-branch-form')[0].action = $('#create-branch-form').data('base-action') + $(this).data('branch-from-urlcomponent');
$('#modal-create-branch-from-span').text($(this).data('branch-from')); $('#modal-create-branch-from-span').text($(this).data('branch-from'));
$($(this).data('modal')).modal('show'); $.find($(this).data('modal')).modal('show');
}); });
} }

View file

@ -65,18 +65,18 @@ export function initRepoClone() {
} }
export function initRepoCommonBranchOrTagDropdown(selector) { export function initRepoCommonBranchOrTagDropdown(selector) {
$(selector).each(function () { $.find(selector).each(function () {
const $dropdown = $(this); const $dropdown = $(this);
$dropdown.find('.reference.column').on('click', function () { $dropdown.find('.reference.column').on('click', function () {
$dropdown.find('.scrolling.reference-list-menu').hide(); $dropdown.find('.scrolling.reference-list-menu').hide();
$($(this).data('target')).show(); $.find($(this).data('target')).show();
return false; return false;
}); });
}); });
} }
export function initRepoCommonFilterSearchDropdown(selector) { export function initRepoCommonFilterSearchDropdown(selector) {
const $dropdown = $(selector); const $dropdown = $.find(selector);
$dropdown.dropdown({ $dropdown.dropdown({
fullTextSearch: true, fullTextSearch: true,
selectOnKeydown: false, selectOnKeydown: false,

View file

@ -15,7 +15,7 @@ export function initRepoDiffFileViewToggle() {
$this.parent().children().removeClass('active'); $this.parent().children().removeClass('active');
$this.addClass('active'); $this.addClass('active');
const $target = $($this.data('toggle-selector')); const $target = $.find($this.data('toggle-selector'));
$target.parent().children().addClass('hide'); $target.parent().children().addClass('hide');
$target.removeClass('hide'); $target.removeClass('hide');
}); });

View file

@ -28,7 +28,7 @@ export function initRepoIssueTimeTracking() {
}); });
$(document).on('click', 'button.issue-delete-time', function () { $(document).on('click', 'button.issue-delete-time', function () {
const sel = `.issue-delete-time-modal[data-id="${$(this).data('id')}"]`; const sel = `.issue-delete-time-modal[data-id="${$(this).data('id')}"]`;
$(sel).modal({ $.find(sel).modal({
duration: 200, duration: 200,
onApprove() { onApprove() {
$(`${sel} form`).trigger('submit'); $(`${sel} form`).trigger('submit');
@ -535,7 +535,7 @@ export function initRepoIssueReferenceIssue() {
const content = $(`#comment-${$this.data('target')}`).text(); const content = $(`#comment-${$this.data('target')}`).text();
const poster = $this.data('poster-username'); const poster = $this.data('poster-username');
const reference = $this.data('reference'); const reference = $this.data('reference');
const $modal = $($this.data('modal')); const $modal = $.find($this.data('modal'));
$modal.find('textarea[name="content"]').val(`${content}\n\n_Originally posted by @${poster} in ${reference}_`); $modal.find('textarea[name="content"]').val(`${content}\n\n_Originally posted by @${poster} in ${reference}_`);
$modal.modal('show'); $modal.modal('show');

View file

@ -42,7 +42,7 @@ export function initRepoCommentForm() {
$branchMenu.find('.item:not(.no-select)').click(function () { $branchMenu.find('.item:not(.no-select)').click(function () {
const selectedValue = $(this).data('id'); const selectedValue = $(this).data('id');
const editMode = $('#editing_mode').val(); const editMode = $('#editing_mode').val();
$($(this).data('id-selector')).val(selectedValue); $.find($(this).data('id-selector')).val(selectedValue);
if ($isNewIssue) { if ($isNewIssue) {
$selectBranch.find('.ui .branch-name').text($(this).data('name')); $selectBranch.find('.ui .branch-name').text($(this).data('name'));
return; return;
@ -58,7 +58,7 @@ export function initRepoCommentForm() {
$selectBranch.find('.reference.column').on('click', function () { $selectBranch.find('.reference.column').on('click', function () {
$selectBranch.find('.scrolling.reference-list-menu').css('display', 'none'); $selectBranch.find('.scrolling.reference-list-menu').css('display', 'none');
$selectBranch.find('.reference .text').removeClass('black'); $selectBranch.find('.reference .text').removeClass('black');
$($(this).data('target')).css('display', 'block'); $.find($(this).data('target')).css('display', 'block');
$(this).find('.text').addClass('black'); $(this).find('.text').addClass('black');
return false; return false;
}); });
@ -145,9 +145,9 @@ export function initRepoCommentForm() {
$(this).parent().find('.item').each(function () { $(this).parent().find('.item').each(function () {
if ($(this).hasClass('checked')) { if ($(this).hasClass('checked')) {
listIds.push($(this).data('id')); listIds.push($(this).data('id'));
$($(this).data('id-selector')).removeClass('hide'); $.find($(this).data('id-selector')).removeClass('hide');
} else { } else {
$($(this).data('id-selector')).addClass('hide'); $.find($(this).data('id-selector')).addClass('hide');
} }
}); });
if (listIds.length === 0) { if (listIds.length === 0) {
@ -155,7 +155,7 @@ export function initRepoCommentForm() {
} else { } else {
$noSelect.addClass('hide'); $noSelect.addClass('hide');
} }
$($(this).parent().data('id')).val(listIds.join(',')); $.find($(this).parent().data('id')).val(listIds.join(','));
return false; return false;
}); });
$listMenu.find('.no-select.item').on('click', function (e) { $listMenu.find('.no-select.item').on('click', function (e) {
@ -182,7 +182,7 @@ export function initRepoCommentForm() {
$(this).addClass('hide'); $(this).addClass('hide');
}); });
$noSelect.removeClass('hide'); $noSelect.removeClass('hide');
$($(this).parent().data('id')).val(''); $.find($(this).parent().data('id')).val('');
}); });
} }
@ -247,7 +247,7 @@ export function initRepoCommentForm() {
$list.find('.selected').html(''); $list.find('.selected').html('');
$list.find('.no-select').removeClass('hide'); $list.find('.no-select').removeClass('hide');
$(input_id).val(''); $.find(input_id).val('');
}); });
} }
@ -450,20 +450,20 @@ export function initRepository() {
// Enable or select internal/external wiki system and issue tracker. // Enable or select internal/external wiki system and issue tracker.
$('.enable-system').on('change', function () { $('.enable-system').on('change', function () {
if (this.checked) { if (this.checked) {
$($(this).data('target')).removeClass('disabled'); $.find($(this).data('target')).removeClass('disabled');
if (!$(this).data('context')) $($(this).data('context')).addClass('disabled'); if (!$(this).data('context')) $.find($(this).data('context')).addClass('disabled');
} else { } else {
$($(this).data('target')).addClass('disabled'); $.find($(this).data('target')).addClass('disabled');
if (!$(this).data('context')) $($(this).data('context')).removeClass('disabled'); if (!$(this).data('context')) $.find($(this).data('context')).removeClass('disabled');
} }
}); });
$('.enable-system-radio').on('change', function () { $('.enable-system-radio').on('change', function () {
if (this.value === 'false') { if (this.value === 'false') {
$($(this).data('target')).addClass('disabled'); $.find($(this).data('target')).addClass('disabled');
if (typeof $(this).data('context') !== 'undefined') $($(this).data('context')).removeClass('disabled'); if (typeof $(this).data('context') !== 'undefined') $.find($(this).data('context')).removeClass('disabled');
} else if (this.value === 'true') { } else if (this.value === 'true') {
$($(this).data('target')).removeClass('disabled'); $.find($(this).data('target')).removeClass('disabled');
if (typeof $(this).data('context') !== 'undefined') $($(this).data('context')).addClass('disabled'); if (typeof $(this).data('context') !== 'undefined') $.find($(this).data('context')).addClass('disabled');
} }
}); });
} }

View file

@ -52,14 +52,14 @@ export function initRepoSettingBranches() {
initRepoCommonFilterSearchDropdown('.protected-branches .dropdown'); initRepoCommonFilterSearchDropdown('.protected-branches .dropdown');
$('.enable-protection, .enable-whitelist, .enable-statuscheck').on('change', function () { $('.enable-protection, .enable-whitelist, .enable-statuscheck').on('change', function () {
if (this.checked) { if (this.checked) {
$($(this).data('target')).removeClass('disabled'); $.find($(this).data('target')).removeClass('disabled');
} else { } else {
$($(this).data('target')).addClass('disabled'); $.find($(this).data('target')).addClass('disabled');
} }
}); });
$('.disable-whitelist').on('change', function () { $('.disable-whitelist').on('change', function () {
if (this.checked) { if (this.checked) {
$($(this).data('target')).addClass('disabled'); $.find($(this).data('target')).addClass('disabled');
} }
}); });
} }