aws-emr-exfiltrate-via-unload
An EMR cluster whose instance profile has s3:PutObject on an attacker-controlled S3 bucket can exfiltrate data via Spark df.write or Hive INSERT OVERWRITE DIRECTORY.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?cluster) ==
AnalyticsService
?cluster provider_type == AWS::EMR::Cluster
?role has EFFECTIVE s3:PutObject on a destination bucket (potentially cross-account or external)
emit
| source type | Identity |
|---|---|
| target type | Storage |
| source | ?role |
| target | <destination S3 bucket (ObjectStorage)> |
| permissions | s3:PutObject |
| conditions | iam_permission resource_policy |
| state logic | ACTIVE when ?role has EFFECTIVE s3:PutObject on the destination bucket AND the destination bucket is reachable (no VPC endpoint restriction preventing writes from the cluster's VPC). CONDITIONAL(resource_policy) if a bucket policy must also grant s3:PutObject from the cluster's account/role to take effect. |
Narrative
EMR cluster {cluster.name} (via instance profile {role.name}) can write/export data to S3 bucket {bucket.name} (s3:PutObject); an attacker with code execution on the cluster can use Spark df.write or Hive INSERT OVERWRITE DIRECTORY to exfiltrate data lake contents to that destination.
Raw rule rules/derived/aws/emr.yaml
id: aws-emr-exfiltrate-via-unload
emits: CanExfiltrate
description: An EMR cluster whose instance profile has s3:PutObject on an attacker-controlled S3 bucket
can exfiltrate data via Spark df.write or Hive INSERT OVERWRITE DIRECTORY.
match:
- - cluster: null
- ExecutesAs
- role: null
where:
- node_type(?cluster) == AnalyticsService
- ?cluster provider_type == AWS::EMR::Cluster
- ?role has EFFECTIVE s3:PutObject on a destination bucket (potentially cross-account or external)
emit:
source_type: Identity
target_type: Storage
source: ?role
target: <destination S3 bucket (ObjectStorage)>
permissions:
- s3:PutObject
conditions:
- iam_permission
- resource_policy
state_logic: ACTIVE when ?role has EFFECTIVE s3:PutObject on the destination bucket AND the destination
bucket is reachable (no VPC endpoint restriction preventing writes from the cluster's VPC). CONDITIONAL(resource_policy)
if a bucket policy must also grant s3:PutObject from the cluster's account/role to take effect.
derived_from:
- <ExecutesAs(aws-emr-executes-as-instance-profile) edge_id>
- <HasPermission(?role -> s3:PutObject) edge_id>
false_positive_note: Only emit when the destination bucket is cross-account (exfiltration to an attacker-controlled
external bucket) OR when the same-account bucket is a high-value target. Writes to the cluster's own
logging/output bucket are not exfiltration. Confirm that the bucket policy grants PutObject from the
instance profile's account/role; cross-account writes require both the IAM role policy AND the destination
bucket policy to permit the write.
narrative: EMR cluster {cluster.name} (via instance profile {role.name}) can write/export data to S3
bucket {bucket.name} (s3:PutObject); an attacker with code execution on the cluster can use Spark
df.write or Hive INSERT OVERWRITE DIRECTORY to exfiltrate data lake contents to that destination.