Back to Checks
aws

DynamoDB table resource-based policy does not allow cross-account access

dynamodb_table_cross_account_access
Service: dynamodbSeverity: medium
OfficialBuilt-inVerified
Categories:trust-boundaries
Resource Type:AwsDynamoDbTable

DynamoDB tables are evaluated for resource-based policies that permit cross-account or public principals.

Tables without a resource policy, or with policies restricted to the same account, are identified as isolated configurations.

Risk

Allowing other accounts to access a table affects:

  • Confidentiality: unauthorized reads/data exfiltration
  • Integrity: writes or deletes by external principals
  • Availability: capacity exhaustion and throttling
  • Cost: owner pays for external requests

If public principals are allowed, exposure can be unrestricted.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks dynamodb_table_cross_account_access

Recommendation

Apply least privilege:

  • Avoid cross-account data access; if required, allow only named principals
  • Constrain with aws:PrincipalOrgID, aws:SourceVpc, aws:PrincipalArn; add Deny guardrails
  • Enable Block Public Access and monitor with IAM Access Analyzer

Remediation

CLI

aws dynamodb delete-resource-policy --resource-arn <resource-arn>

Other

1Open the AWS Console and go to DynamoDB > Tables
2Select <example_resource_name> and open the Permissions tab
3In Resource-based policy, click Delete policy and confirm
4Save changes to remove any cross-account access

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.dynamodb.dynamodb_client import dynamodb_client
from prowler.providers.aws.services.iam.lib.policy import is_policy_public


class dynamodb_table_cross_account_access(Check):
    def execute(self):
        findings = []
        trusted_account_ids = dynamodb_client.audit_config.get(
            "trusted_account_ids", []
        )
        for table in dynamodb_client.tables.values():
            if table.policy is None:
                continue
            report = Check_Report_AWS(metadata=self.metadata(), resource=table)
            report.status = "PASS"
            report.status_extended = (
                f"DynamoDB table {table.name} does not have a resource-based policy."
            )
            if table.policy:
                report.status_extended = f"DynamoDB table {table.name} has a resource-based policy but is not cross account."
                if is_policy_public(
                    table.policy,
                    dynamodb_client.audited_account,
                    is_cross_account_allowed=False,
                    trusted_account_ids=trusted_account_ids,
                ):
                    report.status = "FAIL"
                    report.status_extended = f"DynamoDB table {table.name} has a resource-based policy allowing cross account access."
            findings.append(report)
        return findings