[BUG] AWS CreateAccessKey: unquoted field names make the cross-user filter a no-op (fires on self-key creation)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
Research direction
Start with detections/cloud/aws_createaccesskey.yml and inspect the cross-user filter plus aws_createaccesskey_filter. Run the self-contained SPL reproduction to confirm the current results, then verify the rule excludes self-key creation while retaining cross-user creation, including requests without requestParameters.userName. Review the console-exclusion behavior described in the issue and ensure the final scope is reflected in the rule.
Written by the indexing model from the issue text.
Description
Describe the bug
AWS CreateAccessKey (detections/cloud/aws_createaccesskey.yml, id 2a9b80d3-6340-4345-11ad-212bf3d0d111) is meant to surface a user creating an access key for a different user:
| eval match=if(match(userIdentity.userName,requestParameters.userName),1,0)
| search match=0
Inside eval, the dotted field names are not single-quoted, so SPL parses userIdentity.userName as the . concatenation of the (non-existent) fields userIdentity and userName. Both arguments to match() evaluate to null, match is always 0, and search match=0 keeps every event. As shipped, the filter does nothing: the rule fires on every successful non-console CreateAccessKey, including the routine case of a user rotating their own key.
Repro
Self-contained, with no data needed:
| makeresults count=2
| streamstats count as n
| eval _raw=if(n==1, "{\"userIdentity\":{\"userName\":\"alice\"},\"requestParameters\":{\"userName\":\"alice\"}}", "{\"userIdentity\":{\"userName\":\"alice\"},\"requestParameters\":{\"userName\":\"bob\"}}")
| spath
| eval case=if(n==1,"self: alice creates a key for alice","cross-user: alice creates a key for bob")
| eval match=if(match(userIdentity.userName,requestParameters.userName),1,0)
| eval match_quoted=if('userIdentity.userName'=='requestParameters.userName',1,0)
| table case userIdentity.userName requestParameters.userName match match_quoted
Output:
| case | userIdentity.userName | requestParameters.userName | match (shipped) | match_quoted |
|---|---|---|---|---|
| self: alice creates a key for alice | alice | alice | 0 | 1 |
| cross-user: alice creates a key for bob | alice | bob | 0 | 0 |
The self-key row should be excluded (match=1), but the shipped expression returns 0.
Expected behavior
Only cross-user key creation should produce a result. A minimal fix quotes the fields and compares them directly. match() also treats its second argument as a regex, so a username like svc. would match svcX:
| eval match=if('userIdentity.userName'=='requestParameters.userName',1,0)
| search match=0
One related case to consider: when requestParameters.userName is absent (the key is for the caller), the request is a self-key and should also be excluded, e.g. if(isnull('requestParameters.userName') OR 'userIdentity.userName'=='requestParameters.userName',1,0).
Additional context: the console exclusion no longer matches console calls
The base search excludes console activity with userAgent!=console.amazonaws.com. A real console-issued CreateAccessKey captured from an AWS account in 2026 records a browser user agent (Mozilla/5.0 ... Chrome/...) together with "sessionCredentialFromConsole": "true", not console.amazonaws.com. Keys created in the console today therefore aren't excluded. A scripted caller can also evade the rule by sending the literal console.amazonaws.com user agent.
sessionCredentialFromConsole is not a clean replacement key. It marks console-session credentials, not the client, and AWS's own log examples show CloudShell CLI calls (exec-env/CloudShell) carrying it, including IAM calls. Excluding on it would hide cross-user key creation scripted from CloudShell. Once the cross-user filter works, dropping the console exclusion altogether and suppressing known provisioning principals in aws_createaccesskey_filter may be the better trade-off.
App Version:
- ESCU: reproduced on 5.26.0; SPL unchanged on
develop(64acde7bf6, rule version 11) - Splunk Enterprise 9.3.10, Splunk_TA_aws 7.11.0
- Dominant language
- Python
- Stars
- 1.7k
- Forks
- 494
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 31
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from splunk/security_content
-
Duplicate *http* Pattern in Windows Ngrok Reverse Proxy Usage DetectionPossibly taken @nasbench claimed this 1 day ago. Openbug
Difficulty 1/5 Under an hour Newbie friendliness 72/100
splunk/security_content#4275 · 1 comment · 2 assignees ·
Maintainers usually reply within 1 day
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 72/100
splunk/security_content#4293 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
Lookup replication issue with DA-ESS-ContentUpdate on distributed searchPossibly taken @nasbench claimed this 7 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 35/100
splunk/security_content#4229 · 4 comments ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
splunk/security_content#4220 · 2 comments ·
Maintainers usually reply within 1 day
-
Suggested Enhancement for Detection: Windows AD Short Lived Domain Account ServicePrincipalNameMay be free again @patel-bhavin claimed this 197 days ago, and no pull request is open. Openenhancement
splunk/security_content#3941 · 1 assignee ·
Maintainers usually reply within 1 day
All issues in splunk/security_content
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
PedestrianDynamics/pyFDS-Evac#343 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
theskumar/python-dotenv#708 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Maintainers usually reply within 2 days
-
Docs Timedelta
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
pandas-dev/pandas#69919 ·
Maintainers usually reply within 1 day
-
API documentation
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
zephyrproject-rtos/west#1009 · 2 comments ·
Maintainers usually reply within 3 days