fix(Table_Multiselect_Field): Mitigate reflected XSS due to search (#33443)

* fix(Table_Multiselect Field): Mitigate reflected XSS due to search feature of table multiselect

* fix(Table_Multiselect_Field): Making changes where required

* fix(Table_Multiselect_Field): Making changes where required
This commit is contained in:
Vishal Sindham 2025-08-04 13:36:53 +05:30 committed by GitHub
parent 42c5c41628
commit 8b02229b52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 21 deletions

View file

@ -224,7 +224,8 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
d.label = d.value;
}
let _label = me.get_translated(d.label);
// Sanitize label and description before using them to build HTML
let _label = frappe.utils.escape_html(me.get_translated(d.label));
let html = d.html || "<strong>" + _label + "</strong>";
if (
d.description &&
@ -232,7 +233,10 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
// because it will not visible otherwise
(me.is_title_link() || d.value !== d.description)
) {
html += '<br><span class="small">' + __(d.description) + "</span>";
html +=
'<br><span class="small">' +
__(frappe.utils.escape_html(d.description)) +
"</span>";
}
return $(`<div role="option">`)
.on("click", (event) => {

View file

@ -83,26 +83,33 @@ frappe.ui.form.ControlTableMultiSelect = class ControlTableMultiSelect extends (
const link_field = this.get_link_field();
if (value) {
if (this.frm) {
const new_row = frappe.model.add_child(
this.frm.doc,
this.df.options,
this.df.fieldname
);
new_row[link_field.fieldname] = value;
this.rows = this.frm.doc[this.df.fieldname];
// Trim the value to remove spaces or only if space is only input
value = value.trim();
this.frm.script_manager.trigger(
`${this.df.fieldname}_add`,
this.df.options,
new_row.name
);
} else {
this.rows.push({
[link_field.fieldname]: value,
});
// Only create a pill if the value is a real item from the autocomplete list.
// This prevents creating a pill from raw text when the user clicks away.
if (this.awesomplete.get_item(value)) {
if (this.frm) {
const new_row = frappe.model.add_child(
this.frm.doc,
this.df.options,
this.df.fieldname
);
new_row[link_field.fieldname] = value;
this.rows = this.frm.doc[this.df.fieldname];
this.frm.script_manager.trigger(
`${this.df.fieldname}_add`,
this.df.options,
new_row.name
);
} else {
this.rows.push({
[link_field.fieldname]: value,
});
}
frappe.utils.add_link_title(link_field.options, value, label);
}
frappe.utils.add_link_title(link_field.options, value, label);
}
this._rows_list = this.rows.map((row) => row[link_field.fieldname]);
return this.rows;
@ -165,9 +172,10 @@ frappe.ui.form.ControlTableMultiSelect = class ControlTableMultiSelect extends (
const link_field = this.get_link_field();
const encoded_value = encodeURIComponent(value);
const pill_name = frappe.utils.get_link_title(link_field.options, value) || value;
return `
<button class="data-pill btn tb-selected-value" data-value="${encoded_value}">
<span class="btn-link-to-form">${__(pill_name)}</span>
<span class="btn-link-to-form">${__(frappe.utils.escape_html(pill_name))}</span>
<span class="btn-remove">${frappe.utils.icon("close")}</span>
</button>
`;