Back to Checks
aws

SSM document is not public and shared only with trusted AWS accounts

ssm_documents_set_as_public
Service: ssmSeverity: high
OfficialBuilt-inVerified
Categories:identity-accessinternet-exposed
Resource Type:AwsSsmPatchCompliance

SSM documents are evaluated for public sharing (all) and for shares with AWS accounts outside a defined trusted list. Documents that remain private or are shared only with trusted accounts indicate restricted distribution.

Risk

Public or non-trusted sharing exposes document content, eroding confidentiality of scripts, parameters, and embedded secrets. Adversaries can study runbooks to craft targeted attacks and reuse logic, causing credential leakage and downstream integrity and availability impacts.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks ssm_documents_set_as_public

Recommendation

Apply least privilege to document distribution:

  • Keep documents private; share only with specific trusted account IDs
  • Enable account-level block public sharing for documents
  • Remove secrets from content; use secure parameters
  • Limit who can share or run documents; require reviews and version control

Remediation

CLI

aws ssm modify-document-permission --name <DOCUMENT_NAME> --permission-type Share --account-ids-to-remove all

Terraform

resource "aws_ssm_document" "<example_resource_name>" {
  name          = "<example_resource_name>"
  document_type = "Command"
  content       = jsonencode({
    schemaVersion = "2.2"
    mainSteps     = []
  })
  # Critical: no permissions block -> document remains private (not public/shared)
}

Other

1Open AWS Systems Manager > Documents
2Select the document > Permissions tab > Edit
3Select Private (remove Public/'all')
4Remove any non-trusted AWS account IDs
5Save

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ssm.ssm_client import ssm_client


class ssm_documents_set_as_public(Check):
    def execute(self):
        findings = []
        for document in ssm_client.documents.values():
            report = Check_Report_AWS(metadata=self.metadata(), resource=document)
            trusted_account_ids = ssm_client.audit_config.get("trusted_account_ids", [])
            if ssm_client.audited_account not in trusted_account_ids:
                trusted_account_ids.append(ssm_client.audited_account)
            if not document.account_owners or document.account_owners == [
                ssm_client.audited_account
            ]:
                report.status = "PASS"
                report.status_extended = f"SSM Document {document.name} is not public."
            elif document.account_owners == ["all"]:
                report.status = "FAIL"
                report.status_extended = f"SSM Document {document.name} is public."
            elif all(owner in trusted_account_ids for owner in document.account_owners):
                report.status = "PASS"
                report.status_extended = f"SSM Document {document.name} is shared to trusted AWS accounts: {', '.join(document.account_owners)}."
            elif not all(
                owner in trusted_account_ids for owner in document.account_owners
            ):
                report.status = "FAIL"
                report.status_extended = f"SSM Document {document.name} is shared to non-trusted AWS accounts: {', '.join(document.account_owners)}."

            findings.append(report)

        return findings