From 0d415afdd5062ec7b5998469bf1a0794b1c4843f Mon Sep 17 00:00:00 2001 From: Sagar Vora <16315650+sagarvora@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:02:12 +0530 Subject: [PATCH 1/3] fix: allow unicode chars in field regexes --- frappe/database/query.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/frappe/database/query.py b/frappe/database/query.py index 6cb1117176..09e4aac02d 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -136,11 +136,7 @@ WORDS_PATTERN = re.compile(r"\w+") COMMA_PATTERN = re.compile(r",\s*(?![^()]*\))") # Pattern for validating simple field names (alphanumeric + underscore) -SIMPLE_FIELD_PATTERN = re.compile(r"^\w+$", flags=re.ASCII) - -# Pattern for validating SQL identifiers (aliases, field names in functions) -# More restrictive: must start with letter or underscore -IDENTIFIER_PATTERN = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$", flags=re.ASCII) +SIMPLE_FIELD_PATTERN = re.compile(r"^\w+$") # Pattern for detecting SQL function calls: identifier followed by opening parenthesis FUNCTION_CALL_PATTERN = re.compile(r"^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\(", flags=re.ASCII) @@ -157,7 +153,7 @@ FUNCTION_CALL_PATTERN = re.compile(r"^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\(", flags=re. # - ... as 'Child:field' ALLOWED_FIELD_PATTERN = re.compile( r"^(?:(`[\w\s-]+`|\w+)\.)?(`\w+`|\w+)(?:\s+as\s+(?:`[\w\s-]+`|'[\w\s:-]+'|\w+))?$", - flags=re.ASCII | re.IGNORECASE, + flags=re.IGNORECASE, ) # Regex to parse field names: @@ -2443,7 +2439,7 @@ class SQLFunctionParser: def _is_valid_field_name(self, name: str) -> bool: """Check if a string is a valid field name.""" # Field names should only contain alphanumeric characters and underscores - return IDENTIFIER_PATTERN.match(name) is not None + return SIMPLE_FIELD_PATTERN.match(name) is not None def _validate_alias(self, alias: str): """Validate alias name for SQL injection.""" @@ -2456,7 +2452,7 @@ class SQLFunctionParser: # Alias should be a simple identifier # Note: pypika wraps aliases in backticks, so anything without backticks is safe - if not IDENTIFIER_PATTERN.match(alias): + if not SIMPLE_FIELD_PATTERN.match(alias): frappe.throw( _("Invalid alias format: {0}. Alias must be a simple identifier.").format(alias), frappe.ValidationError, From 17f9ca9819da536993fb31d547b60321a520ed2d Mon Sep 17 00:00:00 2001 From: Sagar Vora <16315650+sagarvora@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:25:13 +0530 Subject: [PATCH 2/3] fix: check for numeric arg first --- frappe/database/query.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/database/query.py b/frappe/database/query.py index 09e4aac02d..67e9d675fc 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -2420,14 +2420,15 @@ class SQLFunctionParser: ).format(arg), frappe.ValidationError, ) - elif self._is_valid_field_name(arg): - self._check_function_field_permission(arg) - return self.engine.table[arg] # Check if it's a numeric string like "1" (for COUNT(1), etc.) elif arg.isdigit(): return int(arg) + elif self._is_valid_field_name(arg): + self._check_function_field_permission(arg) + return self.engine.table[arg] + else: frappe.throw( _( From 2a2350d3a4aabd3f756e2d83af441eb68c6f4184 Mon Sep 17 00:00:00 2001 From: Sagar Vora <16315650+sagarvora@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:25:51 +0530 Subject: [PATCH 3/3] test: ensure fields with accented chars are considered valid --- frappe/tests/test_query.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/tests/test_query.py b/frappe/tests/test_query.py index ccbdb2dcd2..4cf9455ef7 100644 --- a/frappe/tests/test_query.py +++ b/frappe/tests/test_query.py @@ -167,6 +167,7 @@ class TestQuery(IntegrationTestCase): "*", "`tabHas Role`.`name`", "field as `alias with space`", + "frappé", # unicode field names should be valid ] invalid_fields = [