Your S3 buckets are leaking

Think you set your S3 bucket policies correctly? Nothing accidentally public? Trust but verify.

I developed a tool to test your organisation’s S3 setup: heyhabito/s3-bucket-inspector.


S3 configuration can be complicated. You can have conflicting bucket ACL, bucket policy, object ACLs, public access blocks. Tools for inspecting S3 policies don’t always understand the nuances of IP whitelisting and can blurt out false positives or give false negatives. On top of that, your perfectly configured bucket could have been reconfigured by a colleague.

The best way to check for leaky buckets is to actually attempt access:

  • From outside your VPC
  • From a non-whitelisted IP
  • Without an access key

for the operations List, Get, Put and Delete.

Check on a schedule for Continuous Security™, and receive warnings on Slack.


Since the lambdas are run outside your VPC, they will be testing what access is allowed to the public Internet.

The following issues are reported:

  • All keys in your bucket can be listed at http://{bucket_name}
  • Anyone can upload (PUT) objects into your bucket
  • Anyone can delete objects from your bucket
  • An object is publicly readable (Not comprehensive since that would require testing every single key)

It is very unlikely you want the keys of your bucket publicly listable. You definitely don’t want people uploading illegal content to your buckets. Still, you can silence warnings you don’t care about in whitelist.json.

An Example S3 Gotcha

Let’s say you use the bucket policy example from the AWS documentation on restricting access by IP:

  "Version": "2012-10-17",
  "Id": "S3PolicyId1",
  "Statement": [
      "Sid": "IPAllow",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": "arn:aws:s3:::examplebucket/*",
      "Condition": {
         "IpAddress": {"aws:SourceIp": ""},
         "NotIpAddress": {"aws:SourceIp": ""} 

Here the whitelisted IP addresses are allowed to upload objects via unauthenticated PUT requests. However, who is the owner of those new objects?

The owner is 65a011a29cdf8ec533ec3d1ccaae921c AKA Anonymous.

Looking at the policy, you’d think that only the whitelisted IP addresses would be able to access anything. However, the objects are owned by Anonymous, not the bucket owner.

This means that the policy is ignored and anybody on the Internet (Anonymous) can GET the object regardless of IP if they can guess the key.