aws-cloudwatch-tamper-subscription-filter
logs:DeleteSubscriptionFilter or logs:PutSubscriptionFilter on a log group cuts or redirects real-time log delivery to a SIEM, security data lake, or Lambda-based alert processor.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?log_group) ==
LoggingService
?log_group.provider_type == 'AWS::Logs::LogGroup'
?principal has EFFECTIVE logs:DeleteSubscriptionFilter OR logs:PutSubscriptionFilter on ?log_group ARN
?log_group has at least one subscription filter (check logs:DescribeSubscriptionFilters output)
emit
| source type | Identity |
|---|---|
| target type | LoggingService |
| source | ?principal |
| target | ?log_group |
| permissions | logs:DeleteSubscriptionFilter logs:PutSubscriptionFilter |
| conditions | iam_permission scp_or_org_policy service_state |
| state logic | ACTIVE when logs:DeleteSubscriptionFilter or logs:PutSubscriptionFilter is confirmed EFFECTIVE on the log group ARN AND the log group has at least one subscription filter (otherwise the evasion has no security value). CONDITIONAL(service_state) when no subscription filter is confirmed to exist on the log group — the action is possible but the evasion target is absent. logs:PutSubscriptionFilter may be CONDITIONAL(condition_expression) if the required destination (Lambda ARN, Kinesis ARN) is not attacker-controlled. BLOCKED by an explicit deny on the relevant logs: action. This edge is defense evasion — NOT escalation. |
Narrative
{principal.name} can delete or overwrite the subscription filter on {log_group.name} (logs:DeleteSubscriptionFilter / logs:PutSubscriptionFilter), cutting or redirecting real-time log delivery to the SIEM, Lambda alert processor, or security data lake that depends on this filter. Events continue to accumulate in the log group but are no longer shipped for real-time analysis. This is a SIEM blind spot - it does not grant access to any resource.
Raw rule rules/derived/aws/cloudwatch.yaml
id: aws-cloudwatch-tamper-subscription-filter
emits: CanModifyConfiguration
description: logs:DeleteSubscriptionFilter or logs:PutSubscriptionFilter on a log group cuts or redirects
real-time log delivery to a SIEM, security data lake, or Lambda-based alert processor.
match:
- - principal: null
- HasPermission
- log_group: null
where:
- node_type(?log_group) == LoggingService
- ?log_group.provider_type == 'AWS::Logs::LogGroup'
- ?principal has EFFECTIVE logs:DeleteSubscriptionFilter OR logs:PutSubscriptionFilter on ?log_group ARN
- ?log_group has at least one subscription filter (check logs:DescribeSubscriptionFilters output)
emit:
source_type: Identity
target_type: LoggingService
source: ?principal
target: ?log_group
permissions:
- logs:DeleteSubscriptionFilter
- logs:PutSubscriptionFilter
conditions:
- iam_permission
- scp_or_org_policy
- service_state
state_logic: "ACTIVE when logs:DeleteSubscriptionFilter or logs:PutSubscriptionFilter is confirmed EFFECTIVE\
\ on the log group ARN AND the log group has at least one subscription filter (otherwise the evasion\
\ has no security value). CONDITIONAL(service_state) when no subscription filter is confirmed to exist\
\ on the log group \u2014 the action is possible but the evasion target is absent. logs:PutSubscriptionFilter\
\ may be CONDITIONAL(condition_expression) if the required destination (Lambda ARN, Kinesis ARN) is\
\ not attacker-controlled. BLOCKED by an explicit deny on the relevant logs: action. This edge is\
\ defense evasion \u2014 NOT escalation."
confidence: min(contributing_confidences) * 0.85
derived_from:
- ?principal HasPermission ?log_group (logs:DeleteSubscriptionFilter / logs:PutSubscriptionFilter effective
permission)
false_positive_note: "This edge has no evasion value if the log group has no subscription filter \u2014\
\ confirm subscription filter existence via logs:DescribeSubscriptionFilters; if none, emit CONDITIONAL(service_state).\
\ logs:PutSubscriptionFilter requires the resource-based permission on the destination (Lambda / Kinesis)\
\ to allow CloudWatch Logs to invoke it; if the attacker cannot configure the destination, they can\
\ still delete the existing filter (DeleteSubscriptionFilter) to cut the feed. Distinguish DeleteSubscriptionFilter\
\ (definitive cut, ACTIVE) from PutSubscriptionFilter (redirect, may require destination setup \u2014\
\ CONDITIONAL). This does NOT chain to CanExecuteAs or CanEnterAccount. The redirected log stream\
\ going to an attacker-controlled Kinesis may enable data exfiltration \u2014 but that CanExfiltrate\
\ edge is produced by data-plane rules off the destination, not here."
narrative: "{principal.name} can delete or overwrite the subscription filter on {log_group.name} (logs:DeleteSubscriptionFilter\
\ / logs:PutSubscriptionFilter), cutting or redirecting real-time log delivery to the SIEM, Lambda\
\ alert processor, or security data lake that depends on this filter. Events continue to accumulate\
\ in the log group but are no longer shipped for real-time analysis. This is a SIEM blind spot \u2014\
\ it does not grant access to any resource."