Commit ce2a99b
[Security Solution] Allow partial matches on rule name when searching installed rules. (elastic#237496)
**Fixes: elastic#237278**
**Fixes: elastic#97094**
**Fixes: elastic#194066**
## Summary
When a user navigates to `Rules` > `Detection Rules (SIEM)` and wishes
to find all rules matching a partial string on the rule name (like `win`
to get all rules about `Windows`) they receive 0 matches. This is in
contrast to the behavior they experience when searching available
prebuilt "Elastic Rules", where partial name searches are available.
This PR fixes this UX inconsistency by modifying the KQL output
generated by the search query.
Whereas previously a search for `"win"` would have generated the
following KQL:
```sql
(alert.attributes.name: "win" OR
alert.attributes.params.index: "win" OR
alert.attributes.params.threat.tactic.id: "win" OR
...
```
It now treats the `alert.attributes.name` differently, allowing it to
match on partial terms (ie `*win*` instead of `"win"`) and using
`.keyword` index for better special character support.
```sql
(alert.attributes.name.keyword: *win* OR # <-- here
alert.attributes.params.index: "win" OR
alert.attributes.params.threat.tactic.id: "win" OR
...
```
### 🕵️ BUT! .. We only do this for single term searches!
Please note that this approach only applies to single term searches. For
multiple term searches we maintain the "old" way of searching with
quotations `"windows 10 patch"` instead of `*windows 10 patch*` or even
`*windows* *10* *patch*`.
The reasoning here is that since search results are NOT sorted by score,
we want to avoid returning too many matches (wildcard searches match on
_any_ combination of the terms, ie those with `windows` or `10` or
`patch`) which would confuse the user just as they are trying to narrow
down their search results!! (ie 🤔 why am I getting `Linux patch` rules
when I'm asking for `windows 10 patch`??).
## How to test:
To test this PR please checkout the relevant branch and run an instance
of kibana/elasticsearch locally.
1. `Security App` > `Rules` > `Detection Rules (SIEM)`
2. A table of installed rules should appear. Remove all installed
Elastic rules.
3. `Elastic Rules` (filter) > Tick to select all > `Select all X Rules`
> `Bulk actions` > `Delete` > `Delete`
4. Go to `Add Elastic Rules`
5. `Search rules by name` > `win` > `Enter`
6. You should see 5 pages of results (~84 rules)
7. `Install All`
8. All Elastic rules have been installed > `Go back to installed Elastic
rules`
9. Search by rule name > `win` > `Enter`
10. You should see 5 pages of results (~84 rules - same as in Step 6.)
Please feel free to try some additional search queries.
<details>
<summary>
### 👉 Click for additional testing ideas
</summary>
Here are some single term searches:
- `goog`
- `proc`
- `sql` (should include `Postgresql` and `MSSQL`)
- `shell` (should include `Powershell`)
- `inject` (should include `injection`)
- `git` (should include `GitHub`)
- `.exe`
- `pub/sub` (exact matches only)
- `user-agent` (exact matches only)
- `/bin`
- `CVE-2025` (should include partial matches)
- `-` (should return matches with dash in the name like `user-agent`)
- `_` (should return matches with dash in the name like `CAP_SYS_ADMIN`)
- `|` (should return no matches - no elastic rules with this)
And behavior for multiple term searches:
- `AWS` (check the count), then `AWS IAM` (there should be less results
for `AWS IAM`)
- `pub/sub topic` (should be less than for `pub/sub`, note that `pub/sub
top` partial match has no matches!)
- `root` then `root cert` then `root certificate` (the second has no
results, `root certificate` should only return exact matches)
- `proc`, then `process`, then `process injection`, then `potential
process injection` (each should return less results)
</details>
## Screenshots

## Special character support
Note that by switching to wildcard searches (ie `*win*`) on the
`.keyword` index and fully escaping special characters in KQL we'll
**_ALSO_** be allowing special character searches on single search
terms.
For example, searching by `user-agent` will return results that only
match `User-Agent` but not `user` or `agent` individually.
Some other useful example of these approach are searches for: `Pub/Sub`,
`CVE-2025`, `/bin`, `_`, `.exe`.
This support, in addition for escaping the backslash `\` character will
allow us to close the next TWO ISSUES in this epic 🥳 wohoo!!
👉 elastic#97094 (special chars in rule name) and,
👉 elastic#194066 (special chars in tags)
<img width="800" alt="image"
src="https://github.com/user-attachments/assets/5411d8e8-b3f7-4a3f-9863-c64cc2a7df2c"
/>
<img width="800" alt="image"
src="https://github.com/user-attachments/assets/c3589add-9f80-4646-807a-3f0c8a2ec5a7"
/>
### Testing special character support.
In addition to the steps above (installing all elastic rules), we can:
1. Create a rule with special characters: ie `Rule with special chars
(&, *, #, $, ?, >, @, \, /, ", ‘, {, [, ;)`
2. Try some single term matches:
- `@`
- `&` (additional elastic rules with this term should appear).
- `*`
- `"`
- `:`
- `>`
- `{`
- `\` (backslash, this used to break the search under elastic#97094)
## Risks
These are some of the risks that could be identified by using this
approach.
### 1. Dependencies that reuse query logic
Note that the `searchTerm -> KQL` conversion for searching for rules is
used a few places.
- Installed Rules
- Rule Monitoring
- Bulk actions
**Note**: All these paths are tested manually, and form part of the
automated tests.
### 2. Performance (ie `allowLeadingWildcards`)
We're using wildcard searches before and after the search term (ie
`*win*`) in order to replicate the behavior across both 'prebuilt' and
'installed' rules tables. The wildcard AFTER the term (`win*` =>
matching terms like `Windows`) is no problem but the one BEFORE (`*win`
=> matching terms like `Darwin`) could create an issue.
Our [KQL
documentation](https://www.elastic.co/docs/reference/query-languages/kql#_filter_for_documents_using_wildcards)
warns that Kibana UI Advanced Settings have
`query:allowLeadingWildcards` turned off by default. This is for
performance reasons as a leading wildcard can have a large impact when
searching indexes that have millions of terms associated with them.
<img width="2784" height="2120" alt="image"
src="https://github.com/user-attachments/assets/9e0a754c-c30b-453e-a3ae-60a104b13fde"
/>
> By default, leading wildcards are not allowed for performance reasons.
You can modify this with the
[query:allowLeadingWildcards](https://www.elastic.co/docs/reference/kibana/advanced-settings#query-allowleadingwildcards)
advanced setting.
Please note that the [Query DSL docs also
warn](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-query-string-query#query-string-wildcard)
about avoiding this approach.
There is also more info and additional warnings under [Lucene API
docs](https://lucene.apache.org/core/9_12_3/core/org/apache/lucene/search/WildcardQuery.html).
The risk here is two pronged:
1. Users with a lot (millions?) of detection rules will likely have a
degraded search experience as queries will take longer to execute.
2. Leading wildcards appear to be working by default (in contrast to
what is stated in the documentation). But the mere _existence_ of
various settings to avoid them
([`allowLeadingWildcards`](https://www.elastic.co/docs/reference/kibana/advanced-settings#query-allowleadingwildcards),
[`allow_leading_wildcard`](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-query-string-query#query-string-wildcard),
[`analyze_wildcards`](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-query-string-query#query-string-wildcard))
is a risk, because some users may have a special setup we've not been
able to anticipate in our testing, leading to potential issues like this
one: elastic#57828
### Mitigating factors:
1. Please note that in the case of security detection rules, the
prebuilt rules package is _only ~1500 rules_! Users do not manage
millions of rules, they generally manage low thousands or even hundreds.
We've tested 100K rules successfully and there was [_no perceivable
difference in terms of search
performance_](elastic#237496 (comment)).
And this seems to be a realistic test when checking actual usage stats
(our 10 largest users in Sep'25 had between 60-160K installed). Also,
due to current limits on pagination and bulk action logic we would
likely hit different kinds of problems here _before_ search performance
becomes an issue.
2. We've tested all the documented ways to disable leading wildcards,
including disabling them manually (under `Server Management > Advanced
Settings`) and explicitly in the `kibana.yml`. None of them seemed to
affect searches carried out on Saved Objects. This is because our
solution uses the
[`alerting`](http://github.com/elastic/kibana/tree/main/x-pack/platform/plugins/shared/alerting)
plugin under the hood which [converts the filter to KQL without
referring to any UI Advanced
Settings](https://github.com/elastic/kibana/blob/91cab0e1369473846dc2712aa7dfe38b8580a9a5/x-pack/platform/plugins/shared/alerting/server/rules_client/common/build_kuery_node_filter.ts#L23).
And since there is no explicit setting for `allowLeadingWildcards` the
default setting of `true` gets applied instead [inside the
`grammar.peggy`
file](https://github.com/elastic/kibana/blob/91cab0e1369473846dc2712aa7dfe38b8580a9a5/src/platform/packages/shared/kbn-es-query/src/kuery/grammar/grammar.peggy#L12).
### Risks that were found acceptable
In the search for any possible settings that might affect the rollout of
changes under this PR [we did find a
setting](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-wildcard-query#_allow_expensive_queries_7)
inside `elasticsearch.yml` that causes problems with the proposed
solution.
**TL/DR** 👉 `search.allow_expensive_queries=false` breaks the search.💥🤯
<img width="600" alt="image"
src="https://github.com/user-attachments/assets/8d523d15-f832-4488-8c78-4ed60c474d44"
/>
However we also found bigger problems, _this setting also prevents the
installation of prebuilt rules_ (see below), which are a cornerstone of
our security solution.
<img width="600" alt="image"
src="https://github.com/user-attachments/assets/2b8d91e8-29b9-4f06-9f76-6b1edb999fd1"
/>
In other words, the setting `search.allow_expensive_queries=true` has
become _a de-facto requirement of Detection Rules_, that has not yet
been documented. Hence we including it to the
[documentation](https://www.elastic.co/docs/solutions/security/detect-and-alert/detections-requirements)
as part of this PR.
Note also that the errors here are not limited to detection rules.
We found that the setting _also compromised or outright broke a lot of
functionality in Kibana_ 💥🤯 (including Fleet, API Keys, Timelines, Saved
Object search, Tags, Server Monitoring etc). More about this is
[documented in this internal
document](https://docs.google.com/document/d/1HLOXQZFcm1-KBj9DHTqwcF3wDdLOE6CcgUzqzZA2CAg/edit?tab=t.0).
And in this [internal slack
thread](https://elastic.slack.com/archives/C02HA9E8221/p1760694975799469).
So we're assuming that most if not all of our users will have it set to
`true`.
## Checklist
Check the PR satisfies following conditions.
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Follow the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.
- [x] Changes have been socialized with the PM and rest of the team.
- [x] All identified Risks have been properly documented and
investigated. ([internal
investigation](https://docs.google.com/document/d/1HLOXQZFcm1-KBj9DHTqwcF3wDdLOE6CcgUzqzZA2CAg/edit?tab=t.0))
- [x] New requirements added to the technical docs (PR
[elastic#3543](elastic/docs-content#3543), see
[here](https://www.elastic.co/docs/solutions/security/detect-and-alert/detections-requirements))1 parent fff4135 commit ce2a99b
File tree
8 files changed
+460
-46
lines changed- x-pack/solutions/security
- plugins/security_solution
- common
- detection_engine/rule_management
- utils
- public/detection_engine
- rule_management_ui/pages/coverage_overview
- rule_management/api
- test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/basic_license_essentials_tier
8 files changed
+460
-46
lines changedLines changed: 91 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
| 18 | + | |
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
24 | 36 | | |
25 | 37 | | |
26 | 38 | | |
27 | 39 | | |
28 | | - | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
29 | 50 | | |
30 | 51 | | |
31 | 52 | | |
32 | | - | |
33 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
34 | 58 | | |
35 | 59 | | |
36 | | - | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
37 | 70 | | |
38 | 71 | | |
39 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
40 | 113 | | |
41 | 114 | | |
42 | 115 | | |
| |||
74 | 147 | | |
75 | 148 | | |
76 | 149 | | |
77 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
78 | 163 | | |
79 | 164 | | |
80 | 165 | | |
| |||
Lines changed: 32 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
109 | | - | |
110 | 109 | | |
111 | 110 | | |
112 | 111 | | |
| |||
116 | 115 | | |
117 | 116 | | |
118 | 117 | | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
124 | 148 | | |
125 | 149 | | |
126 | 150 | | |
| |||
Lines changed: 47 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
9 | 14 | | |
10 | | - | |
| 15 | + | |
11 | 16 | | |
12 | 17 | | |
13 | 18 | | |
14 | 19 | | |
15 | 20 | | |
16 | | - | |
| 21 | + | |
17 | 22 | | |
18 | 23 | | |
19 | 24 | | |
| |||
42 | 47 | | |
43 | 48 | | |
44 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
45 | 55 | | |
46 | 56 | | |
47 | 57 | | |
48 | | - | |
| 58 | + | |
49 | 59 | | |
50 | 60 | | |
51 | 61 | | |
| |||
65 | 75 | | |
66 | 76 | | |
67 | 77 | | |
68 | | - | |
| 78 | + | |
69 | 79 | | |
70 | 80 | | |
71 | 81 | | |
72 | 82 | | |
73 | 83 | | |
74 | | - | |
| 84 | + | |
75 | 85 | | |
76 | 86 | | |
77 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
Lines changed: 43 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
| 36 | + | |
40 | 37 | | |
41 | | - | |
| 38 | + | |
| 39 | + | |
42 | 40 | | |
43 | 41 | | |
44 | | - | |
| 42 | + | |
45 | 43 | | |
46 | 44 | | |
47 | | - | |
| 45 | + | |
48 | 46 | | |
49 | 47 | | |
50 | 48 | | |
51 | 49 | | |
| 50 | + | |
| 51 | + | |
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
0 commit comments