-
Notifications
You must be signed in to change notification settings - Fork 0
fix(api): refactors the SQL LIKE pattern escaping logic to use a centralized utility function, ensuring consistent and secure handling of special characters across all database queries. #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: cursor_only-issues-20260113-cursor_completion_base_fixapi_refactors_the_sql_like_pattern_escaping_logic_to_use_a_centralized__utility_function_ensuring_consistent_and_secure_handling_of_special_charac
Are you sure you want to change the base?
Changes from all commits
bd89716
7ff69e9
9b21121
0806191
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -984,9 +984,11 @@ def _search_by_like(self, query: str, **kwargs: Any) -> list[Document]: | |
|
|
||
| # No need for dataset_id filter since each dataset has its own table | ||
|
|
||
| # Use simple quote escaping for LIKE clause | ||
| escaped_query = query.replace("'", "''") | ||
| filter_clauses.append(f"{Field.CONTENT_KEY} LIKE '%{escaped_query}%'") | ||
| # Escape special characters for LIKE clause to prevent SQL injection | ||
| from libs.helper import escape_like_pattern | ||
|
|
||
| escaped_query = escape_like_pattern(query).replace("'", "''") | ||
| filter_clauses.append(f"{Field.CONTENT_KEY} LIKE '%{escaped_query}%' ESCAPE '\\\\'") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ClickZetta ESCAPE clause has extra backslashMedium Severity The SQL ESCAPE clause uses |
||
| where_clause = " AND ".join(filter_clauses) | ||
|
|
||
| search_sql = f""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1195,18 +1195,24 @@ def process_metadata_filter_func( | |
|
|
||
| json_field = DatasetDocument.doc_metadata[metadata_name].as_string() | ||
|
|
||
| from libs.helper import escape_like_pattern | ||
|
|
||
| match condition: | ||
| case "contains": | ||
| filters.append(json_field.like(f"%{value}%")) | ||
| escaped_value = escape_like_pattern(str(value)) | ||
| filters.append(json_field.like(f"%{escaped_value}%", escape="\\")) | ||
|
|
||
| case "not contains": | ||
| filters.append(json_field.notlike(f"%{value}%")) | ||
| escaped_value = escape_like_pattern(str(value)) | ||
| filters.append(json_field.notlike(f"%{escaped_value}%", escape="\\")) | ||
|
|
||
| case "start with": | ||
| filters.append(json_field.like(f"{value}%")) | ||
| escaped_value = escape_like_pattern(str(value)) | ||
| filters.append(json_field.like(f"{escaped_value}%", escape="\\")) | ||
|
|
||
| case "end with": | ||
| filters.append(json_field.like(f"%{value}")) | ||
| escaped_value = escape_like_pattern(str(value)) | ||
| filters.append(json_field.like(f"%{value}", escape="\\")) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unescaped value used in "end with" LIKE patternHigh Severity The "end with" case creates |
||
|
|
||
| case "is" | "=": | ||
| if isinstance(value, str): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,38 @@ | |
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def escape_like_pattern(pattern: str) -> str: | ||
| """ | ||
| Escape special characters in a string for safe use in SQL LIKE patterns. | ||
|
|
||
| This function escapes the special characters used in SQL LIKE patterns: | ||
| - Backslash (\\) -> \\ | ||
| - Percent (%) -> \\% | ||
| - Underscore (_) -> \\_ | ||
|
|
||
| The escaped pattern can then be safely used in SQL LIKE queries with the | ||
| ESCAPE '\\' clause to prevent SQL injection via LIKE wildcards. | ||
|
|
||
| Args: | ||
| pattern: The string pattern to escape | ||
|
|
||
| Returns: | ||
| Escaped string safe for use in SQL LIKE queries | ||
|
|
||
| Examples: | ||
| >>> escape_like_pattern("50% discount") | ||
| '50\\% discount' | ||
| >>> escape_like_pattern("test_data") | ||
| 'test\\_data' | ||
| >>> escape_like_pattern("path\\to\\file") | ||
| 'path\\\\to\\\\file' | ||
| """ | ||
| if not pattern: | ||
| return pattern | ||
| # Escape backslash first, then percent and underscore | ||
| return pattern.replace("%", "\\%").replace("_", "\\_").replace("\\", "\\\\") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Escape order is wrong in
|
||
|
|
||
|
|
||
| def extract_tenant_id(user: Union["Account", "EndUser"]) -> str | None: | ||
| """ | ||
| Extract tenant_id from Account or EndUser object. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,12 +86,19 @@ def get_paginate_workflow_app_logs( | |
| # Join to workflow run for filtering when needed. | ||
|
|
||
| if keyword: | ||
| keyword_like_val = f"%{keyword[:30].encode('unicode_escape').decode('utf-8')}%".replace(r"\u", r"\\u") | ||
| from libs.helper import escape_like_pattern | ||
|
|
||
| # Escape special characters in keyword to prevent SQL injection via LIKE wildcards | ||
| escaped_keyword = escape_like_pattern(keyword[:30]) | ||
| keyword_like_val = f"%{keyword[:30]}%" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Escaped keyword created but never usedHigh Severity The code creates |
||
| keyword_conditions = [ | ||
| WorkflowRun.inputs.ilike(keyword_like_val), | ||
| WorkflowRun.outputs.ilike(keyword_like_val), | ||
| WorkflowRun.inputs.ilike(keyword_like_val, escape="\\"), | ||
| WorkflowRun.outputs.ilike(keyword_like_val, escape="\\"), | ||
| # filter keyword by end user session id if created by end user role | ||
| and_(WorkflowRun.created_by_role == "end_user", EndUser.session_id.ilike(keyword_like_val)), | ||
| and_( | ||
| WorkflowRun.created_by_role == "end_user", | ||
| EndUser.session_id.ilike(keyword_like_val, escape="\\"), | ||
| ), | ||
| ] | ||
|
|
||
| # filter keyword by workflow run id | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unescaped keyword used in LIKE pattern
High Severity
The code creates
escaped_keywordby callingescape_like_pattern(keyword)but then uses the original unescapedkeywordvariable inDocumentSegment.content.ilike(f"%{keyword}%", escape="\\"). This defeats the purpose of the escaping and leaves the query vulnerable to SQL injection via LIKE wildcards.