Skip to content

FIX: fold non-ASCII case in the finding title search - #4002

Open
Manohar Paturi (ManoharPaturi) wants to merge 7 commits into
microsoft:mainfrom
ManoharPaturi:fix/findings-title-search-unicode
Open

Manohar Paturi (ManoharPaturi) wants to merge 7 commits into
microsoft:mainfrom
ManoharPaturi:fix/findings-title-search-unicode

Conversation

@ManoharPaturi

Copy link
Copy Markdown
Contributor

Description

Fixes #4001

The finding title search compiled to lower(title) LIKE lower(pattern) on SQLite, whose lower() only folds ASCII letters, so a finding titled CAFÉ security review was found by searching CAFÉ but missed by searching café, while the same data matched both directions on Azure SQL.

Both sides now fold through the per character UnicodeCaseFold, the same machinery the seed value search uses for exactly this reason, with the pattern folded in SQL through the same element so neither backend can mix foldings by lowering one side in Python. Wildcard and bracket escaping is unchanged.

This branch sits on top of #3665, which introduces UnicodeCaseFold; it can be rebased onto main the moment that lands.

Tests and Documentation

Added a regression storing one accented title and one literal wildcard title, asserting the accented title matches in both fold directions and 100% stays a literal query. It fails without the change. The literal wildcard test keeps its existing assertions and now also confirms the fold appears in the compiled SQL for SQL Server. The findings, memory interface, and analytics migration suites pass (816 tests) and ruff is clean.

No documentation change needed, so I did not run JupyText.

SQLite lower() only folds ASCII, so a stored value like CAFE with an accent was found by an exact-case search but missed by a lowercase one. The search now folds the column with the Unicode-aware UnicodeLower used by the harm category filters and folds the pattern in Python.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
str.lower is context sensitive for Greek final sigma, so lowering the term separately from the stored text lost verbatim matches like AS in ASTRO. Both sides now fold through a per character UnicodeCaseFold, and a Greek final sigma regression covers the pair.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
The docstring used a Sphinx reST role that PyRIT's MyST docs do not render, which the pre-commit rest role guard rejects; plain double backticks replace it. A per dialect compile test covers the SQLite registered casefold fallback with its ASCII fast path and the SQL Server LOWER compilation.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
The SQLite casefold compiler and UnicodeLower now build their CASE expression through one helper so the BLOB length guard and ASCII fast path cannot drift, the casefold docstring scopes the sharp s expansion to SQLite, the mssql compile is pinned exactly, a statement level test proves the real search folds both sides in SQL on each dialect, and a sharp s regression pins the SQLite expansion.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
The decorator had landed on the shared helper, whose keyword-only signature cannot take the compiler arguments, so every SQLite UnicodeLower query raised TypeError and analytics requests returned 500. The decorator is back on _sqlite_unicode_lower and the helper takes its arguments keyword only.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
The test built its own select, so folding the pattern in Python while SQL Server mixed foldings passed every test. It now compiles the statement the seed search actually produces through _seed_example_filters for both dialects and asserts the fold wraps column and pattern exactly twice, which fails if either side folds in Python.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
The title search compiled to lower(title) LIKE lower(pattern) on SQLite, whose lower() only folds ASCII, so a CAFE titled finding was found by the exact case and missed by the lowercase query. Both sides now fold through the per character UnicodeCaseFold the seed value search already uses, and the literal wildcard test keeps its escaping assertions.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 6, 2026 11:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Finding title search misses non-ASCII matches on SQLite: case folding is ASCII only

2 participants