From aa4168da7e6a6a6d42914e77191072ecc679e678 Mon Sep 17 00:00:00 2001 From: nitrocode <7775707+nitrocode@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:53:59 -0500 Subject: [PATCH] fix(output): honor include-actions for data exfiltration findings The Data Exfiltration finding category only checked the hardcoded READ_ONLY_DATA_EXFILTRATION_ACTIONS list, so actions added via include-actions in an exclusions file had no effect on this category, even though other finding categories (e.g. Infrastructure Modification) already respect include-actions. Union include-actions into the set of actions checked for data exfiltration, so custom actions opted in via the exclusions config are flagged consistently across finding categories. Fixes #624 --- cloudsplaining/output/policy_finding.py | 11 +++- test/output/test_policy_finding.py | 87 +++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/cloudsplaining/output/policy_finding.py b/cloudsplaining/output/policy_finding.py index 62db6c39..0d61ef38 100644 --- a/cloudsplaining/output/policy_finding.py +++ b/cloudsplaining/output/policy_finding.py @@ -100,11 +100,16 @@ def privilege_escalation(self) -> list[dict[str, Any]]: @property def data_exfiltration(self) -> list[str]: """Returns data exfiltration actions in the policy, if present""" + # Union the built-in read-only data exfiltration actions with any actions the user has + # explicitly opted in to flagging via `include-actions` in the exclusions config, so that + # `include_actions` affects this finding category too (see GH issue #624). `include_actions` + # is already lowercased by Exclusions._include_actions(), and + # allows_specific_actions_without_constraints() lowercases its input for comparison anyway + # (see policy_document.py), so no additional case normalization is needed here. + actions_to_check = list(set(READ_ONLY_DATA_EXFILTRATION_ACTIONS) | set(self.exclusions.include_actions)) return [ action - for action in self.policy_document.allows_specific_actions_without_constraints( - READ_ONLY_DATA_EXFILTRATION_ACTIONS - ) + for action in self.policy_document.allows_specific_actions_without_constraints(actions_to_check) if action.lower() not in self.exclusions.exclude_actions ] diff --git a/test/output/test_policy_finding.py b/test/output/test_policy_finding.py index 4199397a..1f6a44b1 100644 --- a/test/output/test_policy_finding.py +++ b/test/output/test_policy_finding.py @@ -242,3 +242,90 @@ def test_finding_actions_excluded(self): } # print(json.dumps(results, indent=4)) self.assertDictEqual(results, expected_results) + + def test_data_exfiltration_respects_include_actions(self): + """GH issue #624: `include-actions` in the exclusions config should surface actions in the + DataExfiltration finding too, not just be silently ignored by that category.""" + test_policy = { + "Version": "2012-10-17", + "Statement": [{"Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "*"}], + } + policy_document = PolicyDocument(test_policy) + exclusions_cfg = {"include-actions": ["s3:ListBucket"]} + exclusions = Exclusions(exclusions_cfg) + + policy_finding = PolicyFinding(policy_document, exclusions) + results = policy_finding.results + expected_results = { + "ServicesAffected": ["s3"], + "PrivilegeEscalation": { + "severity": "high", + "description": '
These policies allow a combination of IAM actions that allow a principal with these permissions to escalate their privileges - for example, by creating an access key for another IAM user, or modifying their own permissions. This research was pioneered by Spencer Gietzen at Rhino Security Labs. Remediation guidance can be found here.
', + "findings": [], + }, + "ResourceExposure": { + "severity": "high", + "description": 'Resource Exposure actions allow modification of Permissions to resource-based policies or otherwise can expose AWS resources to the public via similar actions that can lead to resource exposure - for example, the ability to modify AWS Resource Access Manager.
', + "findings": [], + }, + "DataExfiltration": { + "severity": "medium", + "description": 'Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as s3:GetObject, ssm:GetParameter*, or secretsmanager:GetSecretValue.
s3:GetObject permissions has a long history of customer data leaks.ssm:GetParameter* and secretsmanager:GetSecretValue are both used to access secrets.rds:CopyDBSnapshot and rds:CreateDBSnapshot can be used to exfiltrate RDS database contents."Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.
', + "findings": [], + }, + "CredentialsExposure": { + "severity": "high", + "description": "Credentials Exposure actions return credentials as part of the API response , such as ecr:GetAuthorizationToken, iam:UpdateAccessKey, and others. The full list is maintained here: https://gist.github.com/kmcquade/33860a617e651104d243c324ddf7992a
", + "findings": [], + }, + # s3:ListBucket also shows up here: this is pre-existing, unrelated `include-actions` + # behavior (statement_detail.py forces any `include-actions` entry into the modify-actions + # check regardless of its access level), not something introduced by this fix. + "InfrastructureModification": {"severity": "low", "description": "", "findings": ["s3:ListBucket"]}, + } + # print(json.dumps(results, indent=4)) + self.assertDictEqual(results, expected_results) + + # (2) Without `include-actions`, the same policy must NOT surface s3:ListBucket as a + # Data Exfiltration finding, since it is not in the default READ_ONLY_DATA_EXFILTRATION_ACTIONS list. + exclusions_cfg = {} + exclusions = Exclusions(exclusions_cfg) + + policy_finding = PolicyFinding(policy_document, exclusions) + results = policy_finding.results + expected_results = { + "ServicesAffected": [], + "PrivilegeEscalation": { + "severity": "high", + "description": 'These policies allow a combination of IAM actions that allow a principal with these permissions to escalate their privileges - for example, by creating an access key for another IAM user, or modifying their own permissions. This research was pioneered by Spencer Gietzen at Rhino Security Labs. Remediation guidance can be found here.
', + "findings": [], + }, + "ResourceExposure": { + "severity": "high", + "description": 'Resource Exposure actions allow modification of Permissions to resource-based policies or otherwise can expose AWS resources to the public via similar actions that can lead to resource exposure - for example, the ability to modify AWS Resource Access Manager.
', + "findings": [], + }, + "DataExfiltration": { + "severity": "medium", + "description": 'Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as s3:GetObject, ssm:GetParameter*, or secretsmanager:GetSecretValue.
s3:GetObject permissions has a long history of customer data leaks.ssm:GetParameter* and secretsmanager:GetSecretValue are both used to access secrets.rds:CopyDBSnapshot and rds:CreateDBSnapshot can be used to exfiltrate RDS database contents."Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.
', + "findings": [], + }, + "CredentialsExposure": { + "severity": "high", + "description": "Credentials Exposure actions return credentials as part of the API response , such as ecr:GetAuthorizationToken, iam:UpdateAccessKey, and others. The full list is maintained here: https://gist.github.com/kmcquade/33860a617e651104d243c324ddf7992a
", + "findings": [], + }, + "InfrastructureModification": {"severity": "low", "description": "", "findings": []}, + } + # print(json.dumps(results, indent=4)) + self.assertDictEqual(results, expected_results)