Skip to content

Build search indicator query from arguments. #40648

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

Merged
merged 27 commits into from
Jul 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c94f4b6
search indicators agentix
omerKarkKatz Jul 16, 2025
9bde5b0
commit
omerKarkKatz Jul 17, 2025
f49c39a
rebase
omerKarkKatz Jul 20, 2025
f20a08c
commit
omerKarkKatz Jul 20, 2025
25b98bb
pre commit fixes
omerKarkKatz Jul 20, 2025
cc73499
revert poetry changes
omerKarkKatz Jul 20, 2025
bd9ef6a
RN
omerKarkKatz Jul 20, 2025
36dd086
merge with master
omerKarkKatz Jul 21, 2025
ea1000e
commit
omerKarkKatz Jul 21, 2025
a228934
Merged master into current branch.
Jul 22, 2025
61eed2a
Bump pack from version CommonScripts to 1.19.90.
Jul 22, 2025
de1db91
review and add qoutes over the query
omerKarkKatz Jul 22, 2025
c84dbd6
Update Packs/CommonScripts/Scripts/SearchIndicatorAgentix/README.md
omerKarkKatz Jul 22, 2025
81c1ad3
fix tags issue (#40669)
jbabazadeh Jul 22, 2025
c0749e1
Update Microsoft Defender for Endpoint (ATP) integration docs (#40630)
kamalq97 Jul 22, 2025
93c868f
Fixed invalid escape character (#40667)
MosheEichler Jul 22, 2025
0a06224
Auto Updated Docker PR from 2025-07-22 GitLab Pipeline ID 4250850 (#4…
content-bot Jul 22, 2025
1aab125
TIM - Fix the domain regex to avoid match backtick at the end (#40660)
MosheEichler Jul 22, 2025
e96a241
[GetEndpointData] Refactor endpoint args and output structure (#40383)
mmhw Jul 22, 2025
6e27c9c
Excessive User Account Lockouts + silent-Suspicious local user accoun…
idovandijk Jul 22, 2025
e774e31
PAN-OS - Security Advisories Vulnerability Check (#40414)
aneeshamore Jul 22, 2025
6f47eaf
pre commit
omerKarkKatz Jul 22, 2025
9b59727
merge with master
omerKarkKatz Jul 22, 2025
99f95b2
bumped base
omerKarkKatz Jul 22, 2025
3c10872
desc
omerKarkKatz Jul 23, 2025
7e9fc22
pre-commit
omerKarkKatz Jul 23, 2025
2d4966c
merge with master
omerKarkKatz Jul 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Packs/Base/ReleaseNotes/1_41_8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Base

Documentation and Metadata improvements.
2 changes: 1 addition & 1 deletion Packs/Base/pack_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Base",
"description": "The base pack for Cortex XSOAR.",
"support": "xsoar",
"currentVersion": "1.41.7",
"currentVersion": "1.41.8",
"author": "Cortex XSOAR",
"serverMinVersion": "6.0.0",
"url": "https://www.paloaltonetworks.com/cortex",
Expand Down
6 changes: 6 additions & 0 deletions Packs/CommonScripts/ReleaseNotes/1_19_90.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

#### Scripts

##### New: SearchIndicatorAgentix

- New: Added a new script- SearchIndicatorAgentix that Searches Cortex XSOAR Indicators.
38 changes: 38 additions & 0 deletions Packs/CommonScripts/Scripts/SearchIndicatorAgentix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
This script searches indicators by specified fields.

## Script Data

---

| **Name** | **Description** |
| --- | --- |
| Script Type | python3 |
| Tags | Utility |
| Cortex XSOAR Version | 6.5.0 |

## Inputs

---

| **Argument Name** | **Description** |
| --- | --- |
| value | A single value or comma separated list of values to search. |
| expirationStatus | The expiration status of the indicator. |
| type | The type of the indicator to search can be a single value or a comma separated list of values. |
| IssuesIDs | The issues that is linked to the indicator can be a single value or a comma separated list of values. |
| size | The number of indicators to return, defaults to a max of 25. |

## Outputs

---

| **Path** | **Description** | **Type** |
| --- | --- | --- |
| foundIndicators.id | The id of the indicator in the XSOAR database. | Unknown |
| foundIndicators.indicator_type | The type of Indicator \(i.e. IP, Domain, URL, etc\) | Unknown |
| foundIndicators.value | The value of the Indicator | Unknown |
| foundIndicators.score | The numeric score of the indicator \(0 = Unknown, 1 = Good, 2 = Suspicious, 3 = Malicious\) | Unknown |
| foundIndicators.verdict | The human readable score/verdict of the Indicator. | Unknown |
| foundIndicators.investigationIDs | The investigations related to the indicator. | Unknown |
| foundIndicators.expiration | The expiration status of the indicator. | Unknown |
| foundIndicators.lastSeen | The timestamp of the last time the indicator was sensitive. | Unknown |
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401

KEYS_TO_EXCLUDE_FROM_QUERY = ["size"]


def prepare_query(args: dict) -> str:
"""
Prepares a query for list-based searches with safe handling

Args:
key (str): Field/attribute to search
value (str/list): Value or list of values to match

Returns:
str: Formatted query string
"""
query_sections = []
for key, values in args.items():
query = ""
if key in KEYS_TO_EXCLUDE_FROM_QUERY:
continue

if not values:
continue

if key == "IssuesIDs":
key = "investigationIDs"

values_as_list = argToList(values)
if len(values_as_list) > 1:
query = " OR ".join(f'{key}:"{str(v).strip()}"' for v in values_as_list)
else:
query = f'{key}:"{str(values_as_list[0]).strip()}"'

query_sections.append(query)

return " AND ".join(f"({qs})" for qs in query_sections) if query_sections else ""


def search_indicators(args):
# search for indicators
query = prepare_query(args)
indicators = demisto.executeCommand("findIndicators", {"query": query, "size": args.get("size")})[0]["Contents"]

# return specific information for found indicators
filtered_indicators = []
fields = ["id", "indicator_type", "value", "score", "expirationStatus", "investigationIDs", "lastSeen"]
for indicator in indicators:
style_indicator = {}
for field in fields:
style_indicator[field] = indicator.get(field, indicator.get("CustomFields", {}).get(field, "n/a"))
style_indicator["verdict"] = scoreToReputation(style_indicator["score"])
filtered_indicators.append(style_indicator)

headers = fields + ["verdict"]
markdown = tableToMarkdown(f"Indicators Found: {query=}", filtered_indicators, headers)
return markdown, filtered_indicators


def main():
args = demisto.args()
try:
readable_output, outputs = search_indicators(args)
results = CommandResults(
outputs_prefix="foundIndicators",
outputs_key_field="id",
readable_output=readable_output,
outputs=outputs,
ignore_auto_extract=True,
)
return_results(results)
except DemistoException as error:
return_error(str(error), error)


if __name__ in ("__main__", "__builtin__", "builtins"):
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
args:
- description: 'A comma-separated list of indicator values to filter the search results (e.g., "1.1.1.1,8.8.8.8").'
name: value
required: false
isArray: true
- description: 'The expiration status of the indicator.'
name: expirationStatus
required: false
predefined:
- expired
- active
- description: 'The type of the indicator to search can be a single value or a comma separated list of values.'
name: type
required: false
isArray: true
- description: 'The IssuesIDs that are linked to the indicator can be a single value or a comma separated list of values.'
name: IssuesIDs
required: false
isArray: true
- defaultValue: "25"
description: The number of indicators to return, defaults to a max of 25.
name: size
comment: |-
This script searches indicators by specified fields.
commonfields:
id: SearchIndicatorAgentix
version: -1
contentitemexportablefields:
contentitemfields:
fromServerVersion: ""
dockerimage: demisto/python3:3.12.8.3296088
enabled: true
name: SearchIndicatorAgentix
outputs:
- contextPath: foundIndicators.id
description: The id of the indicator in the XSOAR database.
- contextPath: foundIndicators.indicator_type
description: The type of Indicator (i.e. IP, Domain, URL, etc).
- contextPath: foundIndicators.value
description: The value of the Indicator.
- contextPath: foundIndicators.score
description: The numeric score of the indicator (0 = Unknown, 1 = Good, 2 = Suspicious, 3 = Malicious).
- contextPath: foundIndicators.verdict
description: The human readable score/verdict of the Indicator.
- contextPath: foundIndicators.investigationIDs
description: The investigations related to the indicator.
- contextPath: foundIndicators.expirationStatus
description: The expiration status of the indicator.
- contextPath: foundIndicators.lastSeen
description: The timestamp of the last time the indicator was sensitive.

runas: DBotWeakRole
script: ''
scripttarget: 0
subtype: python3
tags:
- Utility
type: python
fromversion: 6.5.0
tests:
- No tests (auto formatted)
marketplaces:
- platform
supportedModules:
- agentix
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from Packs.CommonScripts.Scripts.SearchIndicatorAgentix.SearchIndicatorAgentix import prepare_query, search_indicators
import demistomock as demisto


def test_prepare_list_query():
"""
Given: Arguments with multiple values for each field including value, expirationStatus, verdict, and type
When: prepare_query is called with these arguments
Then: Returns a properly formatted query string with OR conditions for multiple values and AND conditions between fields
"""
args = {
"value": ["example.com", "example.org"], # List of values to search
"expirationStatus": ["active"], # Possible expiration statuses
"verdict": ["Benign", "Malicious"], # Possible verdicts
"type": ["Domain", "IP", "URL"], # Indicator
}
res = """(value:"example.com" OR value:"example.org") AND (expirationStatus:"active") AND\
(verdict:"Benign" OR verdict:"Malicious") AND (type:"Domain" OR type:"IP" OR type:"URL")"""
generated_query = prepare_query(args)
assert res == generated_query


def test_prepare_query_with_empty_values():
"""
Given: Arguments with mixed empty lists and populated lists, including custom fields
When: prepare_query is called with these arguments
Then: Returns a query string that excludes empty fields and includes only populated fields
"""
args = {
"value": ["example.com"], # Single value
"expirationStatus": [], # Empty list
"verdict": ["Benign"], # Single verdict
"type": [], # Empty list
"score": ["5", "10"], # Additional field with multiple values
}
res = '(value:"example.com") AND (verdict:"Benign") AND (score:"5" OR score:"10")'
generated_query = prepare_query(args)
assert res == generated_query


def test_prepare_query_edge_cases():
"""
Given: Arguments with special characters, spaces, email formats, empty strings, and mixed data types
When: prepare_query is called with these edge case arguments
Then: Returns a properly formatted query string that handles special characters and excludes empty values
"""
args = {
"value": ["test with spaces", "[email protected]", "192.168.1.1"], # Special characters and formats
"expirationStatus": ["expired"], # Single status
"verdict": [], # Empty verdict list
"type": ["Email", "IP"], # Mixed types
"anotherField": ["value1"], # Single custom field
}
res = """(value:"test with spaces" OR value:"[email protected]" OR value:"192.168.1.1") AND \
(expirationStatus:"expired") AND (type:"Email" OR type:"IP") AND (anotherField:"value1")"""
generated_query = prepare_query(args)
assert res == generated_query


def test_search_indicators_basic_functionality(mocker):
"""
Given: Basic arguments with value, type, and size for searching indicators
When: search_indicators is called with these arguments
Then: Returns markdown output and filtered indicators with proper verdict mapping
"""
args = {"value": "example.com", "type": "Domain", "size": 50}

mock_indicators = [
{
"id": "1",
"indicator_type": "Domain",
"value": "example.com",
"score": 2,
"expirationStatus": "active",
"investigationIDs": ["inv1"],
"expiration": "2024-12-31",
"lastSeen": "2024-01-01",
}
]

mocker.patch.object(demisto, "executeCommand", return_value=[{"Contents": mock_indicators}])
markdown, filtered_indicators = search_indicators(args)

assert "Indicators Found" in markdown
assert len(filtered_indicators) == 1
assert filtered_indicators[0]["id"] == "1"
assert filtered_indicators[0]["verdict"] == "Suspicious"
2 changes: 1 addition & 1 deletion Packs/CommonScripts/pack_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Common Scripts",
"description": "Frequently used scripts pack.",
"support": "xsoar",
"currentVersion": "1.19.89",
"currentVersion": "1.19.90",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down
Loading