Back to Checks
aws

SQS queue policy does not allow public access

sqs_queues_not_publicly_accessible
Service: sqsSeverity: critical
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsSqsQueue

Amazon SQS queue policies are assessed for public access. The finding highlights queues with Allow statements using a wildcard Principal without restrictive conditions, compared to queues that only grant access to the owning account or explicitly trusted principals.

Risk

Public SQS access can expose message data (confidentiality), enable unauthorized send/receive or tampering (integrity), and allow purge/delete operations that disrupt processing (availability). It may also trigger unbounded message ingestion, causing cost spikes and consumer overload.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks sqs_queues_not_publicly_accessible

Recommendation

Apply least privilege on SQS resource policies:

  • Avoid Principal: *; grant access only to specific accounts, roles, or services
  • Add restrictive conditions to tightly scope access
  • Prefer private connectivity and defense-in-depth controls
  • Review policies and audit activity regularly to prevent drift

Remediation

CLI

aws sqs set-queue-attributes --queue-url <example_queue_url> --attributes Policy='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"<example_account_id>"},"Action":"sqs:*","Resource":"<example_queue_arn>"}]}'

Terraform

# Restrict SQS policy to a specific principal (not public)
resource "aws_sqs_queue_policy" "<example_resource_name>" {
  queue_url = "<example_queue_url>"
  policy    = jsonencode({
    Version   = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { AWS = "<example_account_id>" } # CRITICAL: restrict to a specific principal (removes public "*")
      Action    = "sqs:*"
      Resource  = "<example_queue_arn>"
    }]
  })
}

NativeIaC

# CloudFormation: Restrict SQS policy to a specific principal (not public)
Resources:
  QueuePolicy:
    Type: AWS::SQS::QueuePolicy
    Properties:
      Queues:
        - "<example_queue_url>"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: "<example_account_id>" # CRITICAL: restrict access to a specific account (removes public "*")
            Action: "sqs:*"
            Resource: "<example_queue_arn>"

Other

1Open the Amazon SQS console and select the queue
2Go to Permissions (Access policy) and click Edit
3In the JSON policy, replace any "Principal": "*" with "Principal": { "AWS": "<your_account_id>" } or remove those public statements
4Save changes

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.lib.policy import is_condition_block_restrictive
from prowler.providers.aws.services.sqs.sqs_client import sqs_client


class sqs_queues_not_publicly_accessible(Check):
    def execute(self):
        findings = []
        for queue in sqs_client.queues:
            report = Check_Report_AWS(metadata=self.metadata(), resource=queue)
            report.status = "PASS"
            report.status_extended = f"SQS queue {queue.id} is not public."
            if queue.policy:
                for statement in queue.policy["Statement"]:
                    # Only check allow statements
                    if statement["Effect"] == "Allow":
                        if "Principal" in statement and (
                            "*" in statement["Principal"]
                            or (
                                "AWS" in statement["Principal"]
                                and "*" in statement["Principal"]["AWS"]
                            )
                            or (
                                "CanonicalUser" in statement["Principal"]
                                and "*" in statement["Principal"]["CanonicalUser"]
                            )
                        ):
                            if "Condition" in statement:
                                if is_condition_block_restrictive(
                                    statement["Condition"],
                                    sqs_client.audited_account,
                                    True,
                                ):
                                    report.status_extended = f"SQS queue {queue.id} is not public because its policy only allows access from the same account."
                                else:
                                    report.status = "FAIL"
                                    report.status_extended = f"SQS queue {queue.id} is public because its policy allows public access, and the condition does not limit access to resources within the same account."
                                    break
                            else:
                                report.status = "FAIL"
                                report.status_extended = f"SQS queue {queue.id} is public because its policy allows public access."
                                break
            findings.append(report)

        return findings