diff --git a/detections/application/mcp_source_code_secret_search.yml b/detections/application/mcp_source_code_secret_search.yml new file mode 100644 index 0000000000..34db20abab --- /dev/null +++ b/detections/application/mcp_source_code_secret_search.yml @@ -0,0 +1,60 @@ +name: MCP Source Code Secret Search +id: a73b6353-4b34-4a20-8442-76bbb6374616 +version: 1 +creation_date: '2026-06-15' +modification_date: '2026-06-15' +author: Adam Lin +status: production +type: TTP +description: This detection identifies code-search operations through MCP (Model Context Protocol) tool calls that target credential and secret patterns. An adversary who controls an MCP-enabled agent can abuse repository search tools to harvest hard-coded secrets - querying for terms such as password, api_key, secret, token, or provider-specific key prefixes (sk_live, ghp_, AKIA). The search monitors inbound JSON-RPC search_code traffic for these high-signal query terms and surfaces the query and owner so analysts can confirm whether the activity is credential harvesting. +data_source: + - MCP Server +search: | + `mcp_server` direction=inbound method=search_code ( "password" OR "api_key" OR "secret" OR "token" OR "credential" OR "private_key" OR "sk_live" OR "ghp_" OR "AKIA" ) + | eval dest=host + | eval search_query='params.query' + | eval target_owner='params.owner' + | stats count min(_time) as firstTime max(_time) as lastTime values(method) as method values(search_query) as search_query values(target_owner) as target_owner by dest, source + | `security_content_ctime(firstTime)` + | `security_content_ctime(lastTime)` + | table dest firstTime lastTime count source method search_query target_owner + | `mcp_source_code_secret_search_filter` +how_to_implement: This detection requires the MCP Technology Add-on (TA) for Splunk configured to ingest JSON-RPC formatted logs from MCP-enabled AI assistants and agents into the appropriate index with sourcetype mcp:jsonrpc. Ensure the TA parses the params.query and params.owner fields so the code-search term and target organization are available. The macro mcp_source_code_secret_search_filter should be created to allow environment-specific tuning and to allowlist legitimate security-scanning workflows. +known_false_positives: Security teams, secret-scanning tools, and developers legitimately search code for these terms during code review or remediation. Tune the mcp_source_code_secret_search_filter macro to allowlist approved scanning identities and focus on searches originating from unexpected agents or accounts. +references: + - https://github.com/Agent-Threat-Rule/agent-threat-rules + - https://agentthreatrule.org + - https://www.splunk.com/en_us/blog/security/securing-ai-agents-model-context-protocol.html +drilldown_searches: + - name: View the detection results for - "$dest$" + search: '%original_detection_search% | search dest="$dest$"' + earliest_offset: $info_min_time$ + latest_offset: $info_max_time$ + - name: View risk events for the last 7 days for - "$dest$" + search: '| from datamodel Risk.All_Risk | search normalized_risk_object="$dest$" | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`' + earliest_offset: 7d + latest_offset: "0" +finding: + title: 'A credential-pattern code search ($search_query$) was performed on $dest$ via an MCP server tool call against organization $target_owner$. Searching source code for secrets through an agent may indicate credential harvesting.' + entity: + field: dest + type: system + score: 60 +analytic_story: + - Suspicious MCP Activities +asset_type: Web Application +mitre_attack_id: + - T1552.001 +product: + - Splunk Enterprise + - Splunk Enterprise Security + - Splunk Cloud +category: application +security_domain: endpoint +tests: + - name: True Positive Test + attack_data: + - data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/mcp/mcp.log + sourcetype: mcp:jsonrpc + source: mcp.log + test_type: unit diff --git a/detections/application/mcp_suspicious_file_deletion.yml b/detections/application/mcp_suspicious_file_deletion.yml new file mode 100644 index 0000000000..2970496842 --- /dev/null +++ b/detections/application/mcp_suspicious_file_deletion.yml @@ -0,0 +1,64 @@ +name: MCP Suspicious File Deletion +id: 5a2b38a5-b21d-4d8e-a6a8-7adfb47f0557 +version: 2 +creation_date: '2026-06-15' +modification_date: '2026-06-29' +author: Adam Lin +status: production +type: TTP +description: This detection identifies the deletion of security-relevant files, or anomalously high deletion volume, performed through MCP (Model Context Protocol) tool calls. An adversary who has compromised or hijacked an MCP-enabled agent can use its file system or repository tools to destroy data or remove security-relevant files such as SECURITY.md, audit and access logs, or CI and workflow configuration under .github/, achieving data destruction and defense evasion. The search monitors inbound JSON-RPC delete_file operations, matches each deleted path against the editable mcp_security_relevant_deletion_targets macro, and only surfaces hosts that either delete a security-relevant file or exceed a per-host deletion-burst threshold, so the narrowing is performed by the detection logic rather than by deferred tuning. +data_source: + - MCP Server +search: | + `mcp_server` direction=inbound method=delete_file + | eval dest=host + | eval target_path='params.path' + | eval target_repo='params.repo' + | eval is_security_relevant=if(match(target_path, `mcp_security_relevant_deletion_targets`), 1, 0) + | stats count as deletion_count min(_time) as firstTime max(_time) as lastTime values(method) as method values(target_path) as target_path values(target_repo) as target_repo max(is_security_relevant) as is_security_relevant dc(target_path) as distinct_paths by dest, source + | eval is_deletion_burst=if(deletion_count>=10, 1, 0) + | where is_security_relevant=1 OR is_deletion_burst=1 + | eval count=deletion_count + | `security_content_ctime(firstTime)` + | `security_content_ctime(lastTime)` + | table dest firstTime lastTime count source method target_path target_repo is_security_relevant is_deletion_burst distinct_paths + | `mcp_suspicious_file_deletion_filter` +how_to_implement: This detection requires the MCP Technology Add-on (TA) for Splunk configured to ingest JSON-RPC formatted logs from MCP-enabled AI assistants and agents into the appropriate index with sourcetype mcp:jsonrpc. Ensure the TA parses the params.path and params.repo fields so the deleted file path and target repository are available. The detection narrows in-search using the editable mcp_security_relevant_deletion_targets macro (a regular expression of data-destruction and defense-evasion targets such as SECURITY.md, audit and access logs, .github/ CI configuration, and key or secret files) and a per-host deletion-burst threshold of 10 deletions. Edit the mcp_security_relevant_deletion_targets macro to reflect the security-relevant paths in your environment, and tune the threshold or allowlist expected automation in the mcp_suspicious_file_deletion_filter macro. +known_false_positives: Legitimate cleanup, refactoring, and automated housekeeping may delete files through agent tooling. Because the base search only surfaces deletions of security-relevant paths or high-volume deletion bursts, false positives are most likely when automation is authorized to remove CI configuration or rotate key and secret files. Edit the mcp_security_relevant_deletion_targets macro to remove paths your automation legitimately manages, and tune the mcp_suspicious_file_deletion_filter macro to allowlist expected automation identities. +references: + - https://github.com/Agent-Threat-Rule/agent-threat-rules + - https://agentthreatrule.org + - https://www.splunk.com/en_us/blog/security/securing-ai-agents-model-context-protocol.html +drilldown_searches: + - name: View the detection results for - "$dest$" + search: '%original_detection_search% | search dest="$dest$"' + earliest_offset: $info_min_time$ + latest_offset: $info_max_time$ + - name: View risk events for the last 7 days for - "$dest$" + search: '| from datamodel Risk.All_Risk | search normalized_risk_object="$dest$" | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`' + earliest_offset: 7d + latest_offset: "0" +finding: + title: 'A file deletion ($target_path$) was performed on $dest$ via an MCP server tool call against repository $target_repo$. Deletion of security-relevant files or high deletion volume through an agent may indicate data destruction or defense evasion.' + entity: + field: dest + type: system + score: 65 +analytic_story: + - Suspicious MCP Activities +asset_type: Web Application +mitre_attack_id: + - T1485 +product: + - Splunk Enterprise + - Splunk Enterprise Security + - Splunk Cloud +category: application +security_domain: endpoint +tests: + - name: True Positive Test + attack_data: + - data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/mcp/mcp.log + sourcetype: mcp:jsonrpc + source: mcp.log + test_type: unit diff --git a/detections/application/mcp_webhook_persistence_creation.yml b/detections/application/mcp_webhook_persistence_creation.yml new file mode 100644 index 0000000000..78b1771a4e --- /dev/null +++ b/detections/application/mcp_webhook_persistence_creation.yml @@ -0,0 +1,66 @@ +name: MCP Webhook Persistence Creation +id: db95f667-0193-4854-86d6-60cd39d0b3ac +version: 2 +creation_date: '2026-06-15' +modification_date: '2026-06-29' +author: Adam Lin +status: production +type: TTP +description: This detection identifies the creation of repository webhooks that point to untrusted or higher-risk endpoints through MCP (Model Context Protocol) tool calls. Adversaries who gain access to an MCP-enabled agent can register a webhook that points to an attacker-controlled endpoint, giving them durable persistence and a covert exfiltration channel - every future repository event (pushes, pull requests, secrets) is delivered to the external URL without any further interaction. The search monitors inbound JSON-RPC create_webhook operations, extracts the destination host, and only surfaces webhooks whose host is not in the editable mcp_trusted_webhook_domains allowlist or that exhibit higher-risk traits (a plaintext http endpoint or a raw IP address destination), so the narrowing is performed by the detection logic rather than by deferred tuning. +data_source: + - MCP Server +search: | + `mcp_server` direction=inbound method=create_webhook + | eval dest=host + | eval webhook_url='params.url' + | eval target_repo='params.repo' + | eval target_owner='params.owner' + | rex field=webhook_url "^(?https?)://(?[^/:]+)" + | eval is_trusted_domain=if(match(webhook_host, `mcp_trusted_webhook_domains`), 1, 0) + | eval is_plaintext_http=if(url_scheme="http", 1, 0) + | eval is_raw_ip_dest=if(match(webhook_host, "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"), 1, 0) + | where is_trusted_domain=0 OR is_plaintext_http=1 OR is_raw_ip_dest=1 + | stats count min(_time) as firstTime max(_time) as lastTime values(method) as method values(webhook_url) as webhook_url values(webhook_host) as webhook_host values(target_repo) as target_repo values(target_owner) as target_owner max(is_plaintext_http) as is_plaintext_http max(is_raw_ip_dest) as is_raw_ip_dest by dest, source + | `security_content_ctime(firstTime)` + | `security_content_ctime(lastTime)` + | table dest firstTime lastTime count source method webhook_url webhook_host target_repo target_owner is_plaintext_http is_raw_ip_dest + | `mcp_webhook_persistence_creation_filter` +how_to_implement: This detection requires the MCP Technology Add-on (TA) for Splunk configured to ingest JSON-RPC formatted logs from MCP-enabled AI assistants and agents into the appropriate index with sourcetype mcp:jsonrpc. Ensure the TA parses the params.url, params.repo, and params.owner fields so the webhook destination and target repository are available. The detection narrows in-search using the editable mcp_trusted_webhook_domains macro (a regular expression of approved webhook destination domains) and flags plaintext http endpoints and raw IP destinations. Populate the mcp_trusted_webhook_domains macro with the domains of your sanctioned CI/CD and monitoring integrations, and tune the mcp_webhook_persistence_creation_filter macro for any remaining environment-specific exceptions. +known_false_positives: Legitimate automation, CI/CD onboarding, and developer tooling routinely create repository webhooks. Because the base search only surfaces webhooks to untrusted domains, plaintext http endpoints, or raw IP destinations, false positives are most likely before the mcp_trusted_webhook_domains allowlist is populated or when sanctioned integrations use http or IP-based endpoints. Add your known-good destination domains to the mcp_trusted_webhook_domains macro and tune the mcp_webhook_persistence_creation_filter macro for any remaining exceptions. +references: + - https://github.com/Agent-Threat-Rule/agent-threat-rules + - https://agentthreatrule.org + - https://www.splunk.com/en_us/blog/security/securing-ai-agents-model-context-protocol.html +drilldown_searches: + - name: View the detection results for - "$dest$" + search: '%original_detection_search% | search dest="$dest$"' + earliest_offset: $info_min_time$ + latest_offset: $info_max_time$ + - name: View risk events for the last 7 days for - "$dest$" + search: '| from datamodel Risk.All_Risk | search normalized_risk_object="$dest$" | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`' + earliest_offset: 7d + latest_offset: "0" +finding: + title: 'A repository webhook pointing to $webhook_url$ was created on $dest$ via an MCP server tool call against repository $target_repo$. Attacker-controlled webhooks provide persistence and an exfiltration channel by delivering repository events to an external endpoint.' + entity: + field: dest + type: system + score: 60 +analytic_story: + - Suspicious MCP Activities +asset_type: Web Application +mitre_attack_id: + - T1546 +product: + - Splunk Enterprise + - Splunk Enterprise Security + - Splunk Cloud +category: application +security_domain: endpoint +tests: + - name: True Positive Test + attack_data: + - data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/mcp/mcp.log + sourcetype: mcp:jsonrpc + source: mcp.log + test_type: unit diff --git a/macros/mcp_security_relevant_deletion_targets.yml b/macros/mcp_security_relevant_deletion_targets.yml new file mode 100644 index 0000000000..c1c7cea016 --- /dev/null +++ b/macros/mcp_security_relevant_deletion_targets.yml @@ -0,0 +1,8 @@ +name: mcp_security_relevant_deletion_targets +id: ea7cd791-7574-4c18-beab-ca6f1d3452c2 +version: 1 +creation_date: '2026-06-29' +modification_date: '2026-06-29' +author: Adam Lin +description: Editable regular expression of security-relevant deletion targets used by the MCP Suspicious File Deletion detection to narrow file deletions to data-destruction and defense-evasion candidates. Matches security policy files (SECURITY.md), audit and log paths, CI and workflow configuration under .github/, infrastructure-as-code and pipeline definitions, and common security control files. Edit this macro to add or remove paths that are security-relevant in your environment. +definition: '"(?i)(^|/)(security\.md|codeowners|\.github/|\.gitlab-ci\.yml|\.circleci/|jenkinsfile|\.pre-commit-config\.yaml|dependabot\.ya?ml)|(^|/)(audit|access|secure|auth|security)[^/]*\.log$|(^|/)(audit|logs?|var/log|history)/|\.(pem|key|crt|p12|pfx|kdbx)$|(^|/)(\.env|secrets?\.ya?ml|credentials|\.aws/|\.ssh/|known_hosts|authorized_keys)"' diff --git a/macros/mcp_trusted_webhook_domains.yml b/macros/mcp_trusted_webhook_domains.yml new file mode 100644 index 0000000000..2ad5b4ac9f --- /dev/null +++ b/macros/mcp_trusted_webhook_domains.yml @@ -0,0 +1,8 @@ +name: mcp_trusted_webhook_domains +id: b81f64ba-4559-46bb-b1a2-afa2c709bd7b +version: 1 +creation_date: '2026-06-29' +modification_date: '2026-06-29' +author: Adam Lin +description: Editable regular expression of trusted webhook destination domains used by the MCP Webhook Persistence Creation detection. A repository webhook whose destination host matches this expression is treated as an approved CI/CD or monitoring integration and is suppressed. Edit this macro to add the domains of your sanctioned webhook consumers (for example your CI provider, monitoring, or ChatOps endpoints). The default value matches no domain so that, until tuned, every created webhook is surfaced for review. +definition: '"^DISABLED_REPLACE_WITH_TRUSTED_WEBHOOK_DOMAINS$"'