A storage bucket or container that anyone on the internet can read is a data breach waiting for a log entry, and often the logs needed to prove what was read were never switched on. This playbook template covers public Amazon S3 buckets, Azure Blob Storage containers open to anonymous access or shared through over-scoped shared access signatures (SAS), and Google Cloud Storage buckets granted to allUsers or allAuthenticatedUsers. It sets out triggers, roles, decision points, the logs that show what was exposed and for how long, containment settings for each provider, and the breach notification decision. It uses AWS, Microsoft and Google Cloud documentation. It is written for cloud platform, security operations and privacy teams. Adapt the bracketed text before adoption.
How to use this template
- Replace text in square brackets, such as [Organisation], [Cloud Platform Owner], [Data Owner] and [SIEM], with your own names. "Must" is mandatory; "should" is recommended.
- Decision points are marked D1 to D6. Record each decision, who made it and when.
- Setting and log names reflect the cited provider documentation as of October 2026. Re-check them yearly and keep tested commands in your own runbook.
- If the exposure is a leaked storage account key or cloud access key rather than a public bucket, run the Cloud Access Key Leak Playbook in parallel. For the wider process see the Cloud Incident Response Guide.
1. Scope and triggers
1.1 This playbook applies when data in object storage owned by [Organisation], or held for it by a supplier, is or may have been readable or writable by anyone without the intended authorisation.
| Provider | How exposure happens | Where to see it |
|---|---|---|
| Amazon S3 | Bucket policy with "Principal": "*" and no restricting condition; ACL granting AllUsers or AuthenticatedUsers; access point policy; Block Public Access turned off | IAM Access Analyzer for S3 public and cross-account findings; bucket Permissions tab |
| Azure Blob Storage | AllowBlobPublicAccess not set to false and a container at Blob or Container access level; long-lived account or service SAS URL shared publicly | Storage account Configuration blade; Azure Resource Graph query on allowBlobPublicAccess; Azure Policy compliance |
| Google Cloud Storage | IAM or ACL grant to allUsers or allAuthenticatedUsers with public access prevention not enforced; signed URLs shared widely | Bucket permissions; public access prevention status (enforced or inherited) |
1.2 Triggers: a security researcher or journalist report; a cloud security posture alert; an Access Analyzer finding; an anonymous-request alert; the data appearing on a leak site; a secret scanner finding a SAS URL in code.
1.3 Relevant ATT&CK techniques: T1619 Cloud Storage Object Discovery, T1530 Data from Cloud Storage, T1537 Transfer Data to Cloud Account and, where the container was writable, T1485 Data Destruction.
2. Roles and contacts
| Role | Responsibility | Named contact |
|---|---|---|
| [Incident Manager] | Owns the incident, decisions D1 to D6 and the timeline | [Name, phone] |
| [Cloud Platform Owner] | Applies containment settings, preserves configuration and logs; one per provider | [Name per AWS, Azure, Google Cloud] |
| [SOC Analyst] | Log queries, timeline of access, IP enrichment | [Rota] |
| [Data Owner] | Says what the data is, its classification and whose data it is | [From data inventory] |
| [Application Owner] | Confirms which legitimate services read the bucket, so containment does not break production | [Name] |
| [Privacy and Legal] | Breach assessment and notification decisions | [DPO, counsel] |
| [Communications] | Researcher, customer and media responses | [Name] |
2.1 Responder permissions must be granted in advance: changing Block Public Access and bucket policies in AWS, writing the AllowBlobPublicAccess property and regenerating keys in Azure, and setting public access prevention and bucket IAM in Google Cloud.
3. Detection and triage
- Preserve before you fix: export the bucket policy, ACLs, Block Public Access state, container access level, SAS URLs found and object listing with sizes and last-modified times. A configuration change destroys the "before" picture.
- Confirm the exposure from outside with an unauthenticated request to one non-sensitive object, recording the response. Do not download the data set to prove it.
- Classify the data with the [Data Owner]: personal data, special category data, credentials, source code, backups. Search the exposed objects for secrets such as keys, connection strings and tokens. See the Data Classification Guide.
- Establish the exposure window: the time the policy, ACL, container level or SAS was created (CloudTrail management events, Azure activity log, Google Cloud Admin Activity audit logs), to now.
- Establish what was read, using the logs in the table below.
| Provider | Log | What it shows | Limitations |
|---|---|---|---|
| AWS | CloudTrail data events (AWS::S3::Object: GetObject, ListObjects, PutObject, DeleteObject) | Object-level requests, including anonymous ones; delivered about every 5 minutes; log file integrity validation | Off by default, not in Event history, charged extra; no record before you enable it |
| AWS | S3 server access logs | Request records including authentication failures and lifecycle actions | Best-effort delivery: a record may arrive hours later or not at all; must be enabled per bucket |
| Azure | StorageBlobLogs via diagnostic setting; Transactions metric split by Authentication | Filter AuthenticationType == "Anonymous" for public reads; SAS requests show their authentication type | Logs exist only if a diagnostic setting was on; metrics show counts, not objects |
| Google Cloud | Data Access audit logs (DATA_READ, DATA_WRITE) | Authenticated object reads and writes | Off by default; Cloud Audit Logs does not track access to public objects |
| Google Cloud | Cloud Storage usage logs | Requests not covered by audit logs, including public object access | Must have been configured before the exposure |
D1: Severity. Critical: personal, financial, health or credential data exposed, or any write access. High: internal confidential data, read-only. Medium: data already intended to be public but with unintended listing. D2: No logs? If logging was off for any part of the window, [Privacy and Legal] must assume every object exposed in that period was read, unless other evidence shows otherwise.
4. Containment
4.1 Check with the [Application Owner] that no legitimate service depends on public access. If it does (a static website, public downloads), move only the intended public files to dedicated storage, then contain.
| Provider | Containment action | Notes |
|---|---|---|
| Amazon S3 | Turn on all four Block Public Access settings (BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets) on the bucket, or use "Block all public access" from Access Analyzer | The most restrictive combination across organisation, account, bucket and access point levels applies. Existing policies are not deleted, so keep them as evidence and fix them next |
| Azure Blob | Set AllowBlobPublicAccess to false on the storage account | Overrides every container's level; can take up to 30 seconds to apply. The $web static website container stays public |
| Azure SAS (account or ad hoc service SAS) | Regenerate the storage account key that signed it | Revokes all account and service SAS signed with that key. Rotate key2 first if applications use key1. User delegation SAS are not affected |
| Azure SAS (service SAS with stored access policy) | Delete or expire the stored access policy | Revokes only tokens that reference it |
| Azure user delegation SAS | Run az storage account revoke-delegation-keys | Invalidates all user delegation SAS for the account; caching means a short delay before tokens fail |
| Google Cloud Storage | Set public access prevention to enforced on the bucket | allUsers and allAuthenticatedUsers grants remain but stop working (HTTP 401 or 403). Signed URLs are not affected, so rotate the signing service account key if signed URLs leaked |
D3: Write access? If anonymous principals could write or delete, treat the data as untrusted: check for altered objects, planted files and deletions before anyone consumes the contents. In the Microsoft SAS token exposure, an account SAS with full control sat in a public GitHub repository for nearly three years, so anyone holding the link could also overwrite or delete files.
5. Eradication
- Fix the root setting, not just the symptom: remove "Principal": "*" statements or add restricting conditions, remove public ACLs, set containers to Private, remove allUsers grants.
- Rotate every secret found in the exposed data: access keys, database passwords, API tokens, certificates and SAS URLs. These are non-human credentials and each needs an owner and a replacement. See the Secrets Rotation Runbook Template.
- Find siblings: run the Azure Resource Graph query on allowBlobPublicAccess across subscriptions, review Access Analyzer findings in every AWS Region (an analyzer is needed per Region), and list Google Cloud buckets without enforced prevention.
- Find the cause: an infrastructure-as-code template, a manual console change, a supplier, or a SAS generated for "temporary" sharing.
6. Recovery
- Restore integrity from versioned objects or independent backups where D3 found changes.
- Reissue access the right way: IAM roles, managed identities or user delegation SAS with read-only scope and short expiry, which Microsoft recommends over account keys.
- Enable the logs you lacked (CloudTrail data events, server access logs, StorageBlobLogs, Data Access audit logs) and route them to [SIEM].
- Monitor anonymous request metrics and Access Analyzer findings daily for [30] days.
D4: Close containment? The [Cloud Platform Owner] confirms an unauthenticated request now fails and no sibling resources are public before the [Incident Manager] closes.
7. Communication and notification
D5: Notifiable breach? [Privacy and Legal] decide using the exposure window, the data classes, log evidence of access and the D2 rule. Under GDPR, a personal data breach must be reported to the supervisory authority within 72 hours of becoming aware (Article 33) unless it is unlikely to result in a risk to individuals, and individuals must be told where the risk is high (Article 34). See the GDPR Compliance Guide for Security Teams, the Breach Notification Laws by Country Guide and the Data Breach Notification Checklist.
- Researcher: thank them, confirm closure, ask them to delete any copies, and ask what they accessed and when. Their answer is evidence.
- Customers and data subjects: what was exposed, for how long and what they should do.
- Suppliers: if a supplier held the bucket, run the Vendor SaaS Breach Response Playbook in parallel and check your contract's notification terms.
8. Post-incident review
8.1 Within [10] working days, using the Post-Incident Review and Root Cause Analysis Template. D6: decide whether public access is denied by organisation policy by default, with exceptions only through a reviewed process.
8.2 Record: exposure start, detection, containment and notification times; whether logs covered the window; secrets found; why preventive guardrails did not stop it.
Implementation guidance
Guardrails that shorten this playbook.
| Provider | Guardrail | Effect |
|---|---|---|
| AWS | Block Public Access at organisation or account level; IAM Access Analyzer in every Region; CloudTrail data events on sensitive buckets | Public policies and ACLs fail or are ignored; public buckets surface within 30 minutes of a policy change |
| Azure | Azure Policy on allowBlobPublicAccess, Audit first then Deny; SAS expiration policy; disallow Shared Key where possible | No new public accounts; long SAS flagged (the expiration policy warns but does not block) |
| Google Cloud | Organisation policy constraint storage.publicAccessPrevention; Data Access audit logs on sensitive buckets | Public grants fail with 412 when added; existing ones stop working |
| All | Secret scanning for SAS and signed URLs in code; dedicated accounts for public content | Over-scoped links found early; public data separated from private |
Rollout. Phase 1: inventory buckets and containers with owner, classification and public status. Phase 2: monitor anonymous traffic for a representative period, as Microsoft advises, and move legitimate public content to dedicated storage. Phase 3: apply guardrails in audit mode, then enforce; the rollback path is a time-boxed, approved exception for one bucket, never disabling the control organisation-wide. Phase 4: enable data-plane logs on sensitive storage before you need them. Small organisations should start with account-level Block Public Access and AllowBlobPublicAccess false; large ones should enforce at organisation level and alert in [SIEM].
Framework mapping.
| Area | NIST CSF 2.0 | NIST SP 800-53 Rev. 5 |
|---|---|---|
| Data inventory and classification | ID.AM-07 | AC-21 |
| Access policy on storage | PR.AA-05 | AC-3 |
| Secure configuration guardrails | PR.PS-01 | CM-6 |
| Log review of access | RS.AN-03 | AU-6 |
| Containment, eradication, recovery | RS.MI-01, RS.MI-02, RC.RP-01 | IR-4 |
| Notification | RS.CO-02 | IR-6 |
Metrics. Number of public buckets or containers without an approved exception (target zero); mean time from public finding to containment; percentage of sensitive buckets with data-plane logging on; active SAS or signed URLs older than [7] days; percentage of storage accounts with AllowBlobPublicAccess set to false.
Common failure patterns.
- Fixing the bucket before exporting its policy, so the exposure window cannot be proved.
- Assuming no logs means no access, when data-plane logging was simply off.
- Making the bucket private but leaving account SAS or signed URLs valid. Microsoft found its exposed URL in rescans but marked it a false positive, as the Microsoft SAS token exposure page records.
- Rotating the Azure key that applications use without moving them to the other key first.
- Ignoring the secrets inside the exposed backups and logs.
- Checking one AWS Region or one subscription and missing siblings.
Standards and references
- AWS: Blocking public access to your Amazon S3 storage
- AWS: Logging Amazon S3 API calls using AWS CloudTrail
- AWS: Logging requests with server access logging
- Microsoft: Remediate anonymous read access to blob data
- Microsoft: Grant limited access to Azure Storage resources using shared access signatures
- Microsoft: Manage storage account access keys
- Google Cloud: Public access prevention
- Google Cloud: Cloud Audit Logs with Cloud Storage
Related NHI Mgmt Group resources: Cloud Access Key Leak Playbook · Cloud Incident Response Guide · Breach Notification Laws by Country Guide · Data Loss Prevention (DLP) Guide · Microsoft SAS Token Exposure 2023