* [New Rule] AWS API Activity from S3 Browser Client
Detects AWS API activity originating from the S3 Browser application based on the user agent string. S3 Browser is a Windows-based graphical client for managing S3 buckets that is rarely used in enterprise environments but has been observed in use by threat actors for data exfiltration due to its ease of use and bulk download capabilities. This rule was inspired by the Permiso LUCR-3 research which documented Scattered Spider using S3 Browser (v10.9.9) for data theft operations. No usage captured in alert telemetry and only one user utilized this browser in prod data.
Existing Related Coverage: We have several S3-related exfiltration rules covering bucket replication, policy modifications, and ransomware indicators. This new rule closes a gap by detecting a specific attacker tooling fingerprint rather than relying solely on behavioral patterns.
* Update rules/integrations/aws/exfiltration_s3_browser_user_agent.toml
Co-authored-by: Ruben Groenewoud <78494512+Aegrah@users.noreply.github.com>
* [New Rule] AWS API Activity from Uncommon S3 Client by Rare User
This rule detects AWS API activity from S3 Browser and Cyberduck desktop clients based on user agent strings. Both are graphical S3 management tools that provide bulk upload/download capabilities and have been observed in use by threat actors for data exfiltration. S3 Browser usage is specifically documented in the Permiso blog on LUCR-3 (Scattered Spider), while Cyberduck is referenced in the MITRE ATT&CK Threat Emulation of Scattered Spider. The rule uses a New Terms approach on cloud.account.id and user.name to alert only on the first occurrence per user/account, reducing noise from repeated GetObject or PutObject operations while still capturing new suspicious tool usage.
No existing rules currently detect activity based on these specific S3 client user agents. This fills a gap in detecting exfiltration tooling commonly used in post-compromise data theft operations.
* adding space to S3 Browser
---------
Co-authored-by: Ruben Groenewoud <78494512+Aegrah@users.noreply.github.com>
Co-authored-by: Eric Forte <119343520+eric-forte-elastic@users.noreply.github.com>
* [Bug] KQL Validation Add Wildcard w/ Space token value
## Summary
Fixes KQL parser to support wildcard values containing spaces (e.g., `*S3 Browser*`), which work in Kibana but were rejected by our unit tests.
**Issue:** #5750
## Changes
### Grammar (`lib/kql/kql/kql.g`)
- Added `WILDCARD_LITERAL` token with priority 3 to match wildcard patterns containing spaces
- Uses negative lookahead to stop before `or`/`and`/`not` keywords
- Added to `value` rule (not `literal`) so field names remain unaffected
### Parser (`lib/kql/kql/parser.py`)
- Handle new `WILDCARD_LITERAL` token type as wildcards
- Quoted strings (`"*text*"`) now treated as literals, matching Kibana behavior
## Behavior
| Query | Before | After |
|-------|--------|-------|
| `field: *S3 Browser*` | ❌ Parse error | ✅ Wildcard |
| `field: *test*` | ✅ Wildcard | ✅ Wildcard |
| `common.*: value` | ✅ Works | ✅ Works |
| `field: "*text*"` | Wildcard | ✅ Literal (matches Kibana) |
## Test plan
- [x] All 63 existing KQL unit tests pass
- [x] New wildcard-with-spaces patterns parse correctly
- [x] Wildcard field names (`common.*`) still work
- [x] Keywords (`or`, `and`, `not`) correctly recognized as separators
- [x] Tested against rule file from PR #5694
* update pyproject version
* update kibana and kql pyproject.toml versions
update kibana and kql pyproject.toml versions
* update wildcard_literal pattern to account for false matches with leading keywords
Add Negative lookahead at start of Pattern 2 - uses (?!(?:or|and|not)\b) at the start to prevent matching values that begin with keywords like 'not /path*'
* adding NOT keyword token and support for wildcard in the middle of spaced phrase
# KQL Parser Changes - Wildcard Spaces and NOT Prefix Fix
## Overview
This update fixes two issues in the KQL parser:
1. **Wildcard values with spaces** - Values like `*S3 Browser*` now parse correctly
2. **NOT prefix false match** - Values like `not /tmp/go-build*` are no longer incorrectly consumed as a single wildcard literal
## Files Modified
### `lib/kql/kql/kql.g` (Grammar)
**Added `optional_not` rule** to handle `NOT` as an explicit grammar element:
```
?list_of_values: "(" or_list_of_values ")"
| optional_not value
?optional_not: NOT optional_not
|
```
**Expanded `WILDCARD_LITERAL`** with 4 patterns to support all wildcard-with-space cases:
| Pattern | Description | Example |
|---------|-------------|---------|
| 1 | Starts with `*` | `*S3 Browser`, `*S3 Browser*` |
| 2 | Ends with `*` (doesn't start with `*`) | `S3 Browser*` |
| 3a | `*` appears after a space | `S3 B*owser` |
| 3b | `*` appears before a space | `S3* Browser` |
### `lib/kql/kql/parser.py`
Added methods to handle the new grammar rules:
- `list_of_values()` - handles `optional_not value` structure
- `optional_not()` - counts NOT occurrences and wraps values with `NotValue`
### `lib/kql/kql/kql2eql.py`
Added corresponding methods for EQL conversion:
- `list_of_values()` - handles `optional_not value` structure
- `optional_not()` - counts NOT occurrences and wraps with `eql.ast.Not`
## Test Results
All 63 kuery tests pass. Verified wildcard cases:
| Input | Result |
|-------|--------|
| `field: *S3 Browser*` | `field:*S3\ Browser*` |
| `field: S3 Browser*` | `field:S3\ Browser*` |
| `field: *S3 Browser` | `field:*S3\ Browser` |
| `field: S3 B*owser` | `field:S3\ B*owser` |
| `field: S3* Browser` | `field:S3*\ Browser` |
| `field: foo* bar* baz` | `field:foo*\ bar*\ baz` |
| `process.executable: not /tmp/go-build*` | `not process.executable:/tmp/go-build*` |
| `field < value` | `field < value` (range expression, not wildcard) |
## Technical Notes
### Pattern 3a Fix
Pattern 3a requires at least one character AFTER the `*` (uses `[...]+` instead of `[...]*`). This prevents Pattern 2 from incorrectly matching shorter strings like `S3 B*` when the full value is `S3 B*owser`.
### NOT Keyword Handling
The `optional_not` grammar approach explicitly parses `NOT` as a keyword before the value, preventing it from being consumed as part of a wildcard literal. This is safer than regex-only approaches because:
- `NOT` token only matches the exact word "not" (case-insensitive)
- Values like `notafile*` are still parsed as `UNQUOTED_LITERAL`
- Edge case: literal value "not" must be quoted: `field: "not"`
* Changes to Addresses Review Comments
### Changes to Addresses Review Comments @Mikaayenson
1. **Fixed regex patterns to prevent trailing whitespace capture** (`kql.g`)
- Added `(?=\s|$|[()":{}])` lookahead to all WILDCARD_LITERAL patterns
- This ensures patterns stop at boundaries without capturing trailing whitespace
2. **Removed `.rstrip()` workaround** (`parser.py`)
- No longer needed since regex now handles boundaries correctly
3. **Added explicit WILDCARD_LITERAL handling** (`kql2eql.py`)
- Now checks `token.type == "WILDCARD_LITERAL"` explicitly
- Mirrors the approach used in `parser.py`
4. **Added unit tests** (`tests/kuery/test_parser.py`)
- `test_wildcard_with_spaces` - all 4 WILDCARD_LITERAL patterns
- `test_wildcard_with_spaces_and_keywords` - wildcards with `and`/`or` boundaries
- `test_not_prefix_with_wildcard` - NOT keyword not consumed as wildcard
- `test_quoted_wildcard_as_literal` - quoted wildcards are literal strings
- `test_triple_not_optimization` - `not not not foo` → `not foo`
* changed test directory from tmp
* changed format of new tests
* Update pyproject.toml
Update pyproject.toml
---------
Co-authored-by: Eric Forte <119343520+eric-forte-elastic@users.noreply.github.com>
* [New Rules] New Terms rules for malicious Python/Pickle model activity on macOS
Adds three new_terms SIEM detection rules to close the detection gap identified in ia-trade-team#666 where malicious pickle/PyTorch model files execute arbitrary commands via Python deserialization without triggering existing GenAI-parent-gated endpoint rules.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR feedback: broaden descriptions and simplify process.name
- Update descriptions across all three rules to not over-attribute to
pickle/PyTorch — these rules detect any malicious Python activity
(scripts, compromised dependencies, model deserialization, etc.)
- Simplify process.name from explicit enumeration to python* wildcard
since KQL matching is case-insensitive
- Update investigation guides to reflect broader scope of potential
attack vectors
Made-with: Cursor
* Apply suggestion from @DefSecSentinel
* Apply suggestion from @DefSecSentinel
* Apply suggestion from @DefSecSentinel
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary
This PR adds a new detection rule for AWS CloudShell environment creation, based on the **T1059.009 - Command and Scripting Interpreter: Cloud API** technique as documented in the [AWS Threat Technique Catalog](https://aws-samples.github.io/threat-technique-catalog-for-aws/Techniques/T1059.009.html).
AWS CloudShell is a browser-based shell that provides command-line access to AWS resources directly from the AWS Management Console. While convenient for administrators, CloudShell can be abused by adversaries who gain access to compromised console sessions to execute commands, install tools, or interact with AWS services without needing local CLI credentials.
This rule detects the `CreateEnvironment` API call, which occurs when:
- A user launches CloudShell for the **first time**
- A user accesses CloudShell in a **new AWS region** (each region maintains a separate environment)
### Why `CreateEnvironment` instead of `CreateSession`?
`
While both `CreateEnviroment` and `CreateSession` are noted in the catalog for this technique, during testing I observed that:
- **`CreateEnvironment`** is called when a new CloudShell environment is created (first-time user OR new region)
- **`CreateSession`** is called when reconnecting to an existing CloudShell environment that was previously created
By focusing on `CreateEnvironment`, we capture the meaningful signal (new environment creation) while avoiding noise from users simply reconnecting to existing sessions.
* tune credential_access_genai_process_sensitive_file_access.toml to reduce 74% noise on local state
* tune defense_evasion_genai_config_modification.toml to conservatively reduce noise by 19% on file.path
* tune command_and_control_genai_process_unusual_domain.toml to reduce 34% noise by domains
* tune execution_openclaw_agent_child_process.toml to address 99 % of noise with ip/arp
* [Rule Tuning] AWS Access Token Used from Multiple Addresses
Summary
Tuning changes to reduce noise and improve fidelity for the AWS Access Token Used from Multiple Addresses rule. After several tuning this rule is still producing ~2000 alerts/day
- Added aws.cloudtrail.session_credential_from_console exclusion to filter out legitimate console login sessions
- Added Esql.event_provider_count_distinct > 1 condition requiring activity across multiple AWS services to reduce single-service noise
- Changed interval from 5m to 30m to reduce alert frequency
- Updated query time window from 30 minutes to 32 minutes to align with the from setting
- Added min_stack_version = "9.2.0" for the new console credential field (AWS integration 4.6.0+)
Rational
- Console login sessions generate temporary credentials that can appear from multiple IPs during VPN/network transitions
- Requiring activity across multiple AWS service providers increases confidence that the token is being used for broader reconnaissance rather than normal single-service operations
- Longer interval reduces duplicate alerting per access token while still catching the behavior within the 32-minute aggregation window
* Apply suggestions from code review
* Update rules/integrations/aws/initial_access_iam_session_token_used_from_multiple_addresses.toml
* Update initial_access_iam_session_token_used_from_multiple_addresses.toml
* [New] Suspicious Execution from VS Code Extension
Detects suspicious process execution launched from a VS Code extension context (parent command line contains
.vscode/extensions). Malicious extensions can run on startup and drop or execute payloads (e.g. RATs like
ScreenConnect, script interpreters, or download utilities). This covers both script/LOLBin children and
recently created executables from non-Program Files paths, as seen in campaigns such as the fake Clawdbot
extension that installed ScreenConnect RAT.
* Update initial_access_suspicious_execution_from_vscode_extension.toml
* Update initial_access_suspicious_execution_from_vscode_extension.toml
* ++
* Update initial_access_suspicious_execution_from_vscode_extension.toml
* Update initial_access_suspicious_execution_from_vscode_extension.toml
* Update initial_access_suspicious_execution_from_vscode_extension.toml
* Update initial_access_suspicious_execution_from_vscode_extension.toml
* Update initial_access_suspicious_execution_from_vscode_extension.toml