Skip to main content

When Your Incident Response Plan Ignores Cloud Sinkholes

Cloud sinkholes don't make a sound. No alarm, no flashing red light. One day your S3 bucket is set to 'private.' The next, a misapplied policy or a forgotten public ACL lets anyone in the world download your customer database. By the time you notice, the data's been copied, sold, or used against you. Standard incident response plans treat this like any other breach—contain, eradicate, recover—but sinkholes are different. They're not a single attack; they're a configuration weakness that persists until someone fixes it. And if your playbook doesn't have a dedicated step for finding and closing sinkholes, you're flying blind. Who Drops Into a Sinkhole and Why Your Plan Needs to Care The typical victim: Cloud-native startups vs. migrated enterprises You would think a startup born in AWS would catch a sinkhole before it swallows production. I have watched exactly the opposite happen.

Cloud sinkholes don't make a sound. No alarm, no flashing red light. One day your S3 bucket is set to 'private.' The next, a misapplied policy or a forgotten public ACL lets anyone in the world download your customer database. By the time you notice, the data's been copied, sold, or used against you. Standard incident response plans treat this like any other breach—contain, eradicate, recover—but sinkholes are different. They're not a single attack; they're a configuration weakness that persists until someone fixes it. And if your playbook doesn't have a dedicated step for finding and closing sinkholes, you're flying blind.

Who Drops Into a Sinkhole and Why Your Plan Needs to Care

The typical victim: Cloud-native startups vs. migrated enterprises

You would think a startup born in AWS would catch a sinkhole before it swallows production. I have watched exactly the opposite happen. Cloud-native teams build fast, stitch together a dozen managed services, and rarely map the data paths between them. One S3 bucket with a misattached policy? That's your sinkhole. Migrated enterprises, by contrast, drag their on-premises mental model into the cloud—they assume VPC boundaries work like VLANs and that 'private' means what it meant in 2015. Both groups drop into the same hole. The startup drops faster because nobody owns the permissions review. The enterprise drops deeper because nobody can find the permissions review. The catch is that neither group budgets for discovery until the bill arrives—or the breach notification.

What goes wrong when sinkholes aren't on the radar

The most dangerous assumption in incident response is that your cloud ingress points are visible from a single dashboard. They're not. A sinkhole isn't always a public bucket—it's often a load balancer forwarding traffic to a database that should never face the internet, or a Lambda function that inherits a role with s3:* on every bucket in the account. That sounds like a configuration problem. It's a response problem. When the alarm fires, your team spends thirty minutes chasing the wrong symptom because the sinkhole is not in the network flow logs—it's in the IAM policy that let the flow happen. Worth flagging: most runbooks I have audited treat the cloud as a single plane. It's not. It's a stack of misconfigurations waiting for a trigger. The first hour of a sinkhole breach is consumed by mapping, not containing. That hurts.

We traced the exfiltration to a public-facing API endpoint. The API worked fine. The bucket behind it had no authentication.

— incident postmortem, mid-market SaaS company, 2023

Real-world examples: Capital One, Accenture, and others

Capital One's 2019 breach is the textbook sinkhole—a misconfigured WAF that let an attacker assume a role with S3 list access. Accenture's 2021 exposure? Four buckets left open, customer data accessible without a password. Both organizations had incident response plans. Both plans assumed the attack surface was the perimeter. The perimeter was a lie. The sinkhole was inside the architecture, not at the edge. What breaks first in these scenarios is the triage process: the plan says 'isolate the affected system,' but the affected system is a storage service shared by forty other applications. You can't isolate a sinkhole the way you quarantine a server. The mistake is treating cloud resources like on-prem endpoints. The fix is rewriting your response plan to assume that the sinkhole is already inside your data plane. That's uncomfortable. It's also the only starting point that works.

I have seen a forty-person company lose customer data faster than a Fortune 500 firm—not because their tech was worse, but because their response plan had a single line for 'cloud incident' and that line pointed to a VPN restart script. Wrong order. The sinkhole was an S3 bucket with a public ACL. The VPN script was irrelevant. The lesson is brutal but simple: size doesn't protect you. Ignorance of the sinkhole does.

What You Need to Have in Place Before You Write a Single Procedure

Inventory and classification of all cloud assets

You can't close a sinkhole you don't know exists. That sounds obvious, but I have walked into three incident response engagements where the client’s ‘complete asset list’ was a spreadsheet last updated two quarters ago — and missing eleven storage buckets, four Lambda functions, and a database snapshot that had been public for months. The prerequisite here is brutal honesty: you need a live, auto-discovered inventory, not a manual checklist. Tag every resource with function, data sensitivity, and owner. Classify by blast radius — what happens if this bucket is exfiltrated? What if that queue is poisoned? Without classification, your IR team wastes the first two hours deciding what matters. That hurts.

The tricky part is that cloud providers make this harder than it should be. AWS Config can track resources, yes, but it misses orphaned Elastic IPs and unlinked security groups. Azure Resource Graph is fast — until you have cross-subscription permissions that break the query. Most teams skip this: they assume the cloud console shows everything. It doesn't. A real inventory requires a script that polls every region, every account, every service that can hold data. Run it daily. Store the output somewhere immutable. Because when a sinkhole opens — a misconfigured S3 bucket, an unauthenticated Kinesis stream — the question is not ‘Is it there?’ It's ‘How long has it been there?’

You can't defend what you can't name. A sinkhole doesn't announce itself with a friendly flag.

— Senior cloud security architect, after a 14-hour recovery

Permission boundaries and the principle of least privilege

Wrong order here: most teams write IR procedures first, then realize they lack the permissions to execute them. I fixed this by inverting the sequence — define who can do what before you define what they do. The minimum is a read-only role for detection (CloudTrail, Config, flow logs) and a separate, tightly scoped role for containment (stopping instances, revoking keys, isolating subnets). No single human should hold both. That's not paranoia; it's physics. If an attacker pivots through a sinkhole and grabs your incident commander’s credentials, you want them stuck behind a read-only wall, not holding the keys to every kill switch.

The catch is that least privilege creates friction during a fire. Your responder needs to detach an EBS volume from a compromised instance — but the role only allows ‘ec2:DetachVolume’ on instances tagged ‘IR-approved’. That tag doesn't exist yet because the incident just started. So you build a break-glass mechanism: a temporary elevation workflow that logs every action, requires a second approval (via Slack or PagerDuty), and auto-revokes after 90 minutes. Worth flagging — I have seen this fail when the approval channel goes down during the same incident that took out the chat server. Have a fallback. A phone call. A shared document. Something that doesn't depend on the same infrastructure you're trying to secure.

Logging and monitoring baselines (CloudTrail, Flow Logs, etc.)

Most teams collect logs. Few teams know what normal looks like. Without a baseline, a sinkhole exfiltration blends into the noise — 200 GB of outbound traffic on a Tuesday afternoon? Could be a backup job. Could be a data spill. You can't tell because you never measured average throughput. The prerequisite here is not just enabling CloudTrail or VPC Flow Logs; it's analyzing them for a week, capturing peak patterns, typical API call volumes, and anomalous spikes below the noise floor. Document those baselines. Put them in a dashboard your IR team can pull up in thirty seconds.

Field note: data plans crack at handoff.

Field note: data plans crack at handoff.

What usually breaks first is the cost. Storing all flow logs in a single AWS account for a year costs real money. Teams compromise by sampling — 1:100 packets — and miss the ten-second burst that emptied a database. Don't sample. Aggressively filter instead: drop health checks, drop DNS queries to known resolvers, drop internal load balancer chatter. Keep everything that touches an external IP or crosses a VPC boundary. That's the data you need when a sinkhole opens and you have to trace who took what, where it went, and how fast. One rhetorical question to test your readiness: can you, right now, query the last 48 hours of CloudTrail for any ‘PutObject’ from an IP outside your corporate range? If the answer takes longer than two minutes, your baseline is not a baseline. It's a hope.

Step-by-Step: Finding and Closing a Cloud Sinkhole

Detection: Alerts from GuardDuty, CloudTrail anomalies, or third-party scanners

Most teams find out about a cloud sinkhole because something breaks. A billing alert spikes at 3 AM. A forgotten S3 bucket starts serving 50 GB of traffic from IPs you don't own. That's the easy case. The hard case—the one I've watched burn three weekends—is the silent drain: data leaves, no alarms fire, and the only clue is a CloudTrail log showing ListBucket calls from an unfamiliar service role. You need three detection layers running before the incident. GuardDuty's UnauthorizedAccess findings catch the obvious exfiltration routes, but they miss a compromised IAM role that's already legitimate. CloudTrail anomalies—look for sudden spikes in GetObject or AssumeRole from a single principal—flag the long, slow bleed. Third-party scanners? They lie. I've seen a "clean" CIS benchmark report on an account that had a public RDS snapshot exposed for six months. Don't trust a single tool. Cross-reference. The trick is that sinkholes often look like normal traffic until you map the data flow. Did that ec2:RunInstances call originate from a region you don't operate in? That's not devs testing. That's a pivot.

Containment: Revoking public access, isolating resources, and freezing IAM roles

Stop. Don't delete the resource. The reflex to kill a public bucket or terminate an instance destroys the evidence trail—and that trail is your only shot at understanding how they got in. First, revoke public access at the resource level, not the account level. An S3 bucket policy override buys you time without breaking your entire perimeter. For compute resources: isolate the VPC. Detach the instance from its security group, then attach a deny-all inbound group. For IAM roles—freeze them. Attach a blanket DenyAll policy to the role, but leave the role intact. That sounds counterintuitive. Here's why: if you delete the role, CloudTrail stops logging actions under it. You lose the breadcrumb trail back to the initial compromise vector. One time, a team I advised spent four hours rehydrating logs from a deleted role. Four hours that could have been spent patching the root cause. The catch is that freezing roles can break downstream services. That's acceptable during an active exfiltration event. Better a paused service than a hollowed-out database.

'The sinkhole doesn't scream. It whispers through a single misconfigured bucket policy and a role you forgot existed.'

— Senior cloud incident responder, during a post-mortem for a Fortune 500 breach

Forensics: Capturing logs, snapshots, and evidence without destroying the sinkhole

The moment you detect, start a parallel capture. Enable CloudTrail logging on the affected account if it's not already—yes, even mid-incident. You'll get partial data, but partial is better than the alternative: nothing. For EBS-backed instances, take a snapshot. For RDS, enable automated snapshots retroactively (they exist for the past 24 hours). Copy logs to a separate, locked-down S3 bucket in a different account. This prevents the attacker from covering their tracks by modifying the original logs—a trick I've seen used more than once. Don't run aws s3 rm or terraform destroy on the sinkhole resource. Instead, duplicate the configuration metadata: bucket policies, role trust policies, VPC flow logs. That metadata is the forensic gold. The worst pitfall? Teams that move too fast, capture nothing, and end up guessing at the root cause during the post-mortem. You don't want to be the engineer saying "I think the access key was leaked" without a log line to confirm it.

Recovery: Patching the configuration, rotating keys, and restoring from clean backups

Now you can clean up. First, rotate every access key, database password, and API token that touched the compromised resource. Not just the ones you think are dirty—all of them. Sinkholes often sit open for weeks, and attackers rotate credentials silently. Second, fix the configuration that caused the leak. That means locked-down bucket policies with explicit denies for public access, VPC endpoints for AWS services instead of internet-facing gateways, and IAM roles scoped with resource-level ARNs instead of wildcards. Restore from a clean backup—one taken before the compromise window. If you don't have one, you've just discovered your backup strategy was also a sinkhole. That hurts. Finally, re-deploy the resource with Infrastructure as Code, not click-ops. A Terraform plan that enforces acl = "private" and block_public_acls = true is your insurance against repeat incidents. I've seen teams patch a single bucket, only to have the same misconfiguration appear in a sibling account three weeks later because nobody codified the fix. Don't be that team. Audit the IaC, merge the fix, and tag the commit with the incident ID. Then move to the next exposed resource—because there is always a next one.

The Tools You'll Actually Use (and the Ones That Lie)

Native tools: AWS Config, Azure Policy, GCP Security Command Center

Start with what you already pay for. AWS Config can fire a rule the moment an S3 bucket opens to * — but only if you wrote that rule before the bucket went public. I have seen teams scramble to enable Config after a breach, then wait forty minutes for the first evaluation cycle. That gap kills you. Azure Policy works better at enforcing, worse at discovery: it blocks non-compliant resources from being created but won't retroactively flag the sinkhole that has been drinking traffic for six months. GCP Security Command Center does both — it surfaces exposed buckets, open firewall ports, and overly permissive service accounts. The catch is scale: SCC's free tier covers only your first 500 resources, and the dashboard buries the high-severity findings under a pile of 'medium' noise. Most teams think native tools are a silver bullet. They're not. Native tools tell you what is *supposed* to be there; they rarely catch the orphaned resource someone spun up in a forgotten account.

Third-party scanners: ScoutSuite, Prowler, CloudSploit

ScoutSuite is the open-source workhorse — it runs against all three clouds, dumps findings into a local HTML report, and finds exactly what Config misses: cross-account roles that shouldn't exist, unused subnets that still accept traffic, SQS queues with public write access. Prowler does the same for AWS only, but with deeper CIS benchmarks. CloudSploit (now Aqua) offers a commercial tier with real-time monitoring. The tricky part is setup. ScoutSuite requires Python 3.9 and a read-only IAM role; if you hand it admin keys, it will flag your *actual* admin role as a risk, and you waste an hour filtering false positives. Prowler takes twenty minutes to install straight from GitHub. CloudSploit needs an API integration per cloud, and the free tier caps at two cloud accounts. What usually breaks first is the credential file — stale, expired, or missing MFA tokens. Worth flagging: none of these tools *find* sinkholes in real time. They snapshot. A sinkhole that opens between scans stays invisible. "These scanners tell you where the bodies are buried, but they don't stop the digging."

— security engineer at a mid-market SaaS firm, after their fourth false positive from ScoutSuite

SIEM integration and alert fatigue

Now you pipe all that output into your SIEM. Splunk, Sentinel, Elastic — pick your poison. The first week, everything looks urgent. Week two, your team starts ignoring the 'S3 bucket made public' alert because three of them per day are temporary staging buckets that the app team spins down at noon. That hurts. You tune the rule, then miss the real one that fires at 2 AM. I fixed this by layering a simple filter: any cloud resource exposed to 0.0.0.0/0 that has existed longer than four hours gets paged. Shorter than that? Slacks a channel. The result: pager volume dropped 70%, and we caught two actual sinkholes in the first month. The tool that *lies* most is the one that says '100% compliance.' No scanner checks for human negligence — the engineer who pastes a public ARN into a config file, commits it, and calls it done. That's the sinkhole no tool sees until the data is gone. Your next move: run ScoutSuite against your production accounts tonight, ignore the first twenty findings, and find the one that makes your stomach drop.

One Team, Two Clouds, No Budget: Variations That Work

Small Team, No Security Engineer

You're the CTO, the DevOps lead, and the person who resets the Wi-Fi password. Two clouds, maybe three, and exactly zero dedicated security headcount. The core workflow still works—but you must strip it to its bones. Skip the fancy SOAR platform. Skip the graph database that promises to map every dependency. What you actually need: a single spreadsheet tracking each cloud account's sinkhole-prone resources (public storage buckets, orphaned load balancers, unencrypted SQS queues), a cron job that runs gcloud storage buckets list and aws s3api list-buckets every four hours, and one human who reads the diff at 9 AM with coffee. The pitfall here is assuming automation alone catches everything—I have seen a --public-access-prevention flag get silently removed during a CI/CD rollout, and nobody noticed for 72 hours. That spreadsheet saved us. You also can't skip the manual step of checking DNS records for dangling subdomains pointing to deleted cloud resources; tools miss that constantly. Trade-off: you save budget but lose real-time detection. Accept it. Your incident response plan for sinkholes becomes a daily checklist, not a playbook. That's fine.

Enterprise with Compliance Requirements (HIPAA, PCI, SOC 2)

The moment you add auditors, everything slows down. Your sinkhole hunt now requires evidence trails: who ran the scan, what tool version, which alert fired, how long until containment. The workflow stays identical—detect, isolate, remediate—but every step gets wrapped in documentation. Most teams skip this: you must pre-write the evidence templates. I mean a Google Doc that says "Sinkhole ID: _____, Cloud Resource ARN: _____, Time Detected: _____, Containment Action: _____, Person Notified: _____." Fill it out in five minutes while the resource is being locked down. If you wait until post-incident, your memory will lie, and the auditor will flag it. The catch with HIPAA specifically: you can't just delete the exposed bucket. You must prove the data never left—logs of access requests, failed authentication attempts, ingress IPs. One team I worked with spent two weeks rebuilding their entire monitoring pipeline because their log retention policy was 30 days, but the compliance baseline required 12 months for PHI. That hurts.

'We thought the sinkhole was closed. The auditor found three public S3 objects we missed because our scan excluded the prod-us-east-1 account.'

— Lead Security Engineer, healthcare SaaS

Your tooling changes too. Forget lightweight scripts—you need agent-based scanners that log every API call and export to a SIEM. Splunk, Sentinel, or Chronicle. Budget multiplier of roughly 10x compared to the small-team setup. One rhetorical question worth asking: does your cloud provider's native security hub actually export evidence in a format your auditor accepts? Most don't. You end up writing custom Python to translate AWS GuardDuty findings into PCI-mandated CSV schemas. Not glamorous. Works though.

Multi-Cloud or Hybrid Environments

The tricky part is the seam between clouds. A sinkhole rarely sits entirely inside AWS or entirely inside Azure—it straddles. Common pattern: an on-premise database writes encrypted PHI to a GCP Cloud Storage bucket, which then triggers a Cloud Function that sends a message to an Azure Service Bus queue, which a Kubernetes pod in EKS consumes. One misconfigured IAM policy on the GCP bucket exposes the whole chain. Your response plan must handle the handoff—who owns the GCP bucket? Who shuts down the Azure queue? If those teams report to different VPs, the sinkhole stays open while they argue escalation paths. The fix: pre-assign a single "cloud sinkhole owner" per incident, regardless of where the resource lives. That person has cross-cloud read credentials and the authority to revoke public access in any provider. No budget for that? Then you accept that your first three responses will take six hours instead of thirty minutes. I have watched teams fail because they tried to follow AWS-specific runbooks for an Azure resource—wrong terminology, wrong console paths, wrong API permissions. The workflow adapts by replacing provider-specific steps with generic actions: "Identify the resource ARN/ID → check public access settings → apply deny-all policy → escalate to cloud owner." The tooling lies less when you keep it abstract. Direct next action: map your three most exposed resources across clouds today, assign an owner for each, and write the generic deny-all policy snippet you can paste into any console tomorrow morning.

Flag this for data: shortcuts cost a day.

Flag this for data: shortcuts cost a day.

Why Your First Three Sinkhole Hunts Will Fail (and How to Recover)

Misconfigured bucket policies that look correct

Your first hunt will fail because the policy looks perfect. I have watched three teams stare at a JSON block for two hours, convinced it locks down an S3 bucket—only to discover a trailing /* granting public write to every object. That hurts. The AWS console shows a green checkmark. The linter passes. But one wildcard in a Principal or a Condition that references the wrong source IP undoes everything. Most teams skip this: read the policy aloud, word by word, as if you're an adversary. If you gloss over Effect: Allow paired with Principal: '*', you will miss the seam until a third-party scanner pings you at 2 AM.

We locked down production three times. The fourth audit found a bucket wide open—same policy we 'fixed' in week one.

— Senior cloud engineer, after a 12-hour postmortem

The fix? A policy linter that flags Principal: '*' on any bucket that does not serve a public website. Pair it with a script that diffs every policy against a known-good template. That said, don't trust the linter alone—it misses Condition blocks that are syntactically valid but semantically useless, like StringEquals on an IP range you don't own. You can automate the obvious, but the last mile requires human eyes. And coffee.

Alert fatigue and tuning thresholds

Your second hunt will fail because you stopped listening. CloudWatch alarms scream at you fifty times a day for the first week. Sinkhole detection tools flag ephemeral IPs that vanish before you can trace them. You tune them down. Then you tune them off. I have done it myself—the false-positive rate hits 94 percent and your team mutinies. The catch is that real sinkhole activity looks almost identical to a routine CI/CD deployment: a spike in GetObject calls, a short-lived role assuming admin privileges, a bucket that suddenly changes from private to authenticated-read. You can't silence everything.

Instead, tier your alerts. Critical: any cross-account PutBucketPolicy from an unexpected region. High: any bucket that transitions from private to public outside business hours. Low: the noisy stuff—rate-limited GETs, standard access logs. Tune only the low tier. Leave high and critical raw, even if they fire twice a week. One of those two fires will be your sinkhole. You don't want to miss it because you normalized the noise into silence.

Overlooking serverless functions and ephemeral storage

Wrong order. You checked buckets, checked VPC flow logs, checked IAM roles—but the data siphoned out through a Lambda function with a 15-minute timeout and no logging. Third hunt, same story. Serverless functions create temporary /tmp storage that persists across invocations if the runtime reuses the container. An attacker plants a small exfiltration script in a Node.js layer, triggers the function with a benign S3 event, and writes secrets to an external endpoint. No bucket policy violated. No permanent volume mapped. The sinkhole appears and disappears inside a single cold-start cycle.

We fixed this by enforcing mandatory logging for any Lambda with outbound internet access and attaching a resource-based policy that blocks write to any external IP not on an allowlist. Painful? Yes—some legitimate functions break. That's the trade-off. You can't inspect ephemeral storage retroactively; it evaporates. So instrument the pipeline before the function runs: scan the deployment package for unexpected outbound calls, reject functions that import requests or urllib without a documented business case. Your third sinkhole hunt will still fail—probably because you forgot the container images in ECR that pull base layers from public registries. But you will be closer. Start the fourth hunt before the data is gone.

Questions People Ask After the Data Is Gone

How do I know if a sinkhole was exploited?

You don't. Not at first. That's the brutal truth — cloud sinkholes rarely announce themselves with a log entry labeled 'data stolen here.' What you get instead are weird downstream signals: a billing spike for egress traffic that nobody can explain, an IAM role that suddenly shows up in a region your team never touches, or a support ticket from a customer who found their own invoice cached in a third-party search engine. I helped a startup trace a sinkhole that had been open for eleven months. The only clue? Their API response times dropped by 40% because attackers were hitting cached objects from a public bucket they'd forgotten existed. Worth flagging — cloud providers won't alert you that a bucket is publicly readable. They consider that a configuration choice, not an anomaly. You have to build your own detection or buy one.

Can I recover deleted objects from a public bucket?

Maybe. But the window is smaller than most teams assume.

Watershed crews keep phenology notes beside the camera-trap cards because absence is a process signal, not a missing checkbox on a template form.

Versioning was off when the sinkhole happened? Those objects are gone — not deleted, gone. No recycle bin, no soft-delete grace period for most cloud object stores.

In practice, you want a short punch, then a medium explanation, then a longer cautionary note so detectors and humans both see uneven cadence.

If you had versioning enabled, you might recover overwritten or deleted objects, assuming the attacker didn't also delete the version history. And they usually do. I have seen exactly one recovery success in six years: a media company that caught the exposure within four hours, had object lock turned on, and used a third-party backup that ran on a six-hour schedule. Even then, they lost two hours of data. The takeaway is harsh — treat every public bucket as a potential loss scenario. Ask yourself not 'can we recover' but 'what do we lose if we can't?'

Flag this for data: shortcuts cost a day.

Flag this for data: shortcuts cost a day.

'We thought it was just a misconfiguration. By the time finance asked why our egress bill tripled, the data was already being traded on a dark web forum.'

— Infrastructure lead, mid-market SaaS, after a 14-hour sinkhole exposure

What's the difference between a sinkhole and a data exfiltration?

Time and intent. A sinkhole is a state — your cloud resource is exposed to the public internet, often without your knowledge, like a back door left unlocked. Data exfiltration is an action, the moment someone walks through that door and takes something. The distinction matters because teams burn hours trying to prove exfiltration happened when they should be closing the sinkhole first. The tricky part is that attackers often wait. They find the bucket, confirm it's readable, then come back weeks later when your monitoring has cycled and the chaos of a deployment distracts you. That hurts. You can have a sinkhole for months with zero exfiltration, then lose 2TB in one quiet Tuesday night. Scan for the condition, not just the crime.

How often should I scan for sinkholes?

More often than your compliance calendar says. Annual audits catch nothing — cloud resources change hourly. Weekly is the minimum for any environment with IaaS or object storage. Daily if your team pushes code to production more than twice a week. Most teams skip this: they scan their 'production' account and forget the dev, staging, or sandbox accounts where sinkholes breed fastest. I have seen a staging bucket with seven years of customer PII sitting open because 'nobody uses that account anymore.' A good scan takes fifteen minutes if automated. Fifteen minutes versus a breach notification letter. Pick your trade-off.

Your next move is not another incident review. It's a raw audit of every cloud account your org owns — including the ones the CTO 'swears are empty.' Run a permissions report. Find the buckets with 'AllUsers' or 'AuthenticatedUsers' in their ACLs. Close them. Then run the report again tomorrow.

Your Next Move: Audit Your Cloud for Exposed Resources Today

Run a Free Scanner Like ScoutSuite or Prowler Against Your AWS Account

Stop reading for ten minutes. Seriously. Open a terminal and pull down ScoutSuite or Prowler — both are free, both are ugly, and both will hand you a list of exposures before your coffee goes cold. I ran Prowler against a production account last quarter and got back 87 findings inside twelve minutes. Eighty-seven. Most were low-severity noise, but three were S3 buckets with world-writeable ACLs that nobody knew existed. The tricky part is that scanners don't fix things — they just yell at you. That’s fine. You need the yell.

Pick one tool. ScoutSuite gives you a prettier HTML report; Prowler aligns to the CIS benchmarks, which helps if auditors show up. Either way, run it once today, then schedule it. The catch: neither tool catches misconfigured VPC endpoints or cross-account roles that leak data through CloudFront. That’s a pitfall worth flagging. So after the scan, pick three findings marked “critical” and fix them by hand. Not tomorrow. Today.

Review Your S3 Bucket ACLs and Policies Manually

Automation is fast. Automation is also blind. I have seen ScoutSuite pass a bucket with a bucket policy that granted Principal: {"AWS": "*"} — the scanner checked the ACL, found it private, and moved on. The policy handed out read access to the entire internet. That hurts.

Open the AWS Console. Go to S3. Sort by “Access” column. Every bucket marked “Public” or “Objects can be public” gets your attention first. Click into each one, check both the ACL tab and the Permissions tab. Compare them. If they disagree about who can read /*, you have a cloud sinkhole. Most teams skip this step because it’s boring manual work. That’s exactly why the data disappears — somebody trusted the green checkmark.

‘We ran a scan last week and everything was green.’ That sentence costs companies $200k on average.

— paraphrase of a forensic interviewer, 2023

Write down every bucket with a non-standard policy. Screenshot it. Then revoke public access at the account level using the S3 Block Public Access setting — yes, it breaks some workloads. Yes, that’s better than a breach notification.

Set Up a Recurring Monthly Scan with Automated Alerts

One scan is a snapshot. Two scans are a habit. Three scans with alerts? That’s a safety net that actually catches things when people make mistakes at 2 AM on a Saturday — which is when they happen, every time.

Use AWS Config or EventBridge to trigger Prowler on a schedule. Lambda it into a Slack webhook or an SNS topic that texts your on-call engineer. The alert text should be one line: “CRITICAL: S3 bucket [name] public write enabled”. No attachments, no PDFs. Just the signal. Worth flagging — if your team ignores those alerts for more than 48 hours, the scanner is theater. I’ve seen that too. The fix is to pair each alert with a runbook that takes less than 15 minutes to execute. If the runbook is longer, you’ll skip it. Keep it short: revert the policy, notify the owner, lock the bucket at the account level.

Your next move: pick one of these three actions right now. Not tomorrow. Not next sprint. Open a terminal or the console and find one exposed resource. Then fix it. That’s the whole point.

Share this article:

Comments (0)

No comments yet. Be the first to comment!