Merge pull request #38835 from AarDG10/fix-formatters

fix(formatters)!: escape input fields
This commit is contained in:
Aarol D'Souza 2026-04-27 12:26:38 +05:30 committed by GitHub
commit cdc6dca582
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 7 deletions

View file

@ -392,7 +392,7 @@ def make_links(columns, data):
def update_field_types(columns):
for col in columns:
if col.fieldtype in ("Link", "Dynamic Link", "Currency") and col.options != "Currency":
col.fieldtype = "Data"
col.fieldtype = "HTML Editor"
col.options = ""
return columns

View file

@ -1,6 +1,7 @@
import frappe
from frappe import format
from frappe.tests import IntegrationTestCase
from frappe.utils.formatters import format_value
class TestFormatter(IntegrationTestCase):
@ -17,3 +18,37 @@ class TestFormatter(IntegrationTestCase):
self.assertEqual(format(100000, df, doc, format="#,###.##"), "$ 100,000.00")
frappe.db.set_default("currency", None)
def test_safe_formatting(self):
"""Test that in certain field types, the values are escaped."""
payload = "<script>alert('testing')</script>"
sanitized_payload = "&lt;script&gt;alert(&apos;testing&apos;)&lt;/script&gt;"
data_df = frappe._dict({"fieldname": "book_name", "fieldtype": "Data"})
self.assertEqual(format_value(payload, data_df), sanitized_payload)
text_df = frappe._dict({"fieldname": "book_description", "fieldtype": "Text"})
self.assertEqual(format_value(payload, text_df), sanitized_payload)
html_df = frappe._dict({"fieldname": "book_title", "fieldtype": "HTML Editor"})
self.assertEqual(format_value(payload, html_df), payload)
editor_df = frappe._dict({"fieldtype": "Text Editor"})
formatted_editor = format_value("<b>Bold</b>", editor_df)
self.assertEqual(formatted_editor, "<div class='ql-snow'><b>Bold</b></div>")
ltext_df = frappe._dict({"fieldname": "book_long_description", "fieldtype": "Long Text"})
self.assertEqual(format_value(payload, ltext_df), sanitized_payload)
select_df = frappe._dict({"fieldtype": "Select", "parent": "Task"})
value = "Open"
self.assertEqual(format_value(value, select_df), "Open")
self.assertEqual(format_value(payload, select_df), sanitized_payload)
link_df = frappe._dict({"fieldtype": "Link", "options": "User"})
self.assertEqual(format_value(payload, link_df, doc=None), sanitized_payload)
doc = frappe._dict({"__link_titles": {"User::attacker@example.com": "<svg onload=alert(1)>"}})
formatted = format_value("attacker@example.com", link_df, doc)
self.assertIn("&lt;svg", formatted)
self.assertEqual(format_value(payload, df=None), sanitized_payload)

View file

@ -60,6 +60,8 @@ def format_value(value, df=None, doc=None, currency=None, translated=False, form
value = frappe._(value)
if not df:
if isinstance(value, str):
return frappe.utils.escape_html(value)
return value
elif df.get("fieldtype") == "Date":
@ -99,7 +101,8 @@ def format_value(value, df=None, doc=None, currency=None, translated=False, form
elif df.get("fieldtype") in ("Text", "Small Text"):
if not BLOCK_TAGS_PATTERN.search(value):
return frappe.safe_decode(value).replace("\n", "<br>")
escaped_value = frappe.utils.escape_html(frappe.safe_decode(value))
return escaped_value.replace("\n", "<br>")
elif df.get("fieldtype") == "Markdown Editor":
return frappe.utils.markdown(value)
@ -124,21 +127,28 @@ def format_value(value, df=None, doc=None, currency=None, translated=False, form
elif df.get("fieldtype") in ["Link", "Dynamic Link"]:
if not doc or not doc.get("__link_titles") or not df.options:
return value
return frappe.utils.escape_html(cstr(value))
doctype = df.options
if df.get("fieldtype") == "Dynamic Link":
if not df.parent:
return value
return frappe.utils.escape_html(cstr(value))
meta = frappe.get_meta(df.parent)
_field = meta.get_field(df.options)
doctype = _field.options
return doc.__link_titles.get(f"{doctype}::{value}", value)
link_title = doc.__link_titles.get(f"{doctype}::{value}", value)
return frappe.utils.escape_html(cstr(link_title))
elif df.get("fieldtype") == "Select":
if isinstance(value, str):
return frappe._(value, context=df.parent or "")
translated_value = frappe._(value, context=df.parent or "")
return frappe.utils.escape_html(translated_value)
elif df.get("fieldtype") == "HTML Editor":
return value
if isinstance(value, str):
value = frappe.utils.escape_html(value)
return value