Backblaze B2 stores get exposed through a mechanism distinct from AWS ACLs but equally simple to accidentally trigger: a bucket-level type that controls whether every file in the bucket is publicly downloadable. It is set at bucket creation but can be changed at any time. Flip the type to allPublic and every file becomes downloadable by any caller who knows or can guess its URL: no credentials, no signed request. Crucially, this is anonymous download of known keys, not anonymous enumeration. There is no unauthenticated way to list what a public B2 bucket contains, so exposure comes from someone fetching individual file URLs they already know or can guess.

How B2 bucket types work

Every B2 bucket has one of two types. The type is set at creation in the Backblaze console or via API, but it is not fixed there. It can be switched at any time with b2_update_bucket:

  • allPrivate: the safe baseline. Files require an authorization token or a signed download URL to retrieve. No unauthenticated access.
  • allPublic: every file in the bucket is publicly downloadable without any credentials. A caller who constructs the correct URL for a file can download it.

The bucket type applies uniformly across all files in the bucket. There is no per-object visibility override in the way that S3 has object-level ACLs. If the bucket is allPublic, every file is accessible.

Why teams set allPublic. Backblaze B2 has a long-standing partnership with Cloudflare that makes egress from B2 to Cloudflare free. For teams hosting media, static assets, or large file downloads, this is a significant cost advantage over AWS or GCS egress rates. The typical deployment pattern: B2 bucket for storage, Cloudflare as the CDN layer in front, with B2 set to allPublic so Cloudflare can fetch origin files without managing authorization tokens. The problem is that allPublic exposes the bucket directly, not just through Cloudflare, and many deployments leave the B2 origin reachable alongside the CDN.

Why you can't just list a public B2 bucket

This is where B2 diverges sharply from S3, and where transplanted intuition often goes wrong. On S3, an open bucket frequently leaks its full contents to an anonymous ?list-type=2 request. B2 does not work this way. Both of B2's listing surfaces require authentication, regardless of bucket type:

  • Native B2 API. The b2_list_file_names call returns a paginated list of files, but it requires an application key with the listFiles capability. It is never an unauthenticated call.
  • S3-compatible endpoint. B2's S3-compatible API (exposed at s3.<region>.backblazeb2.com) implements SigV4, and every list operation (including ?list-type=2) must be SigV4-signed. This holds even for allPublic buckets: there is no anonymous ListBucketResult response to obtain. You cannot enumerate a public B2 bucket the way you can an open S3 bucket, and the S3-style enumeration probes that work against AWS simply return an auth error here.

What allPublic actually grants is anonymous download of individual objects whose keys you already know. Given a filename, anyone can fetch it unauthenticated:

https://f<NNN>.backblazeb2.com/file/<bucket-name>/<file-key>

The f<NNN> download host is not something you can synthesize by guessing a shard number. It is the account's downloadUrl, returned by b2_authorize_account, so the correct host must be known or observed from a real link rather than fabricated. The same object is also reachable over the S3-compatible path:

https://<bucket-name>.s3.<region>.backblazeb2.com/<file-key>

Exposure of an allPublic bucket is therefore a function of key knowledge, not free enumeration. Filenames leak from front-end code, shared links, referrers, and predictable naming schemes (backup-2026-06-01.sql, avatars/<user-id>.png). The common real-world path is worse: allPublic buckets are often paired with broad application keys embedded in client-side code for direct-upload flows. When such a leaked key carries listFiles, an attacker enumerates the bucket authenticated and then downloads every object anonymously. The listing capability, not the bucket type, is what turns a public bucket into a fully harvestable one.

To check whether a specific B2 file URL is publicly downloadable, paste it into the open-bucket viewer.

What gets exposed

The content profile of a publicly accessible B2 bucket depends on why it was made public. For teams using B2 for the Cloudflare egress model, the exposed content is typically application assets: images, video, downloadable files, and build artifacts. That's a relatively contained exposure.

The more dangerous case is teams using B2 as a low-cost backup destination. B2's pricing makes it attractive for bulk backup storage, and allPublic is sometimes set inadvertently: chosen at bucket creation because the console default is visible and the implications aren't obvious, or because a previous bucket was public and the workflow was copy-pasted. A publicly accessible backup bucket can contain database exports, application state, and credential-bearing configuration files.

Remediation

The fix is one setting. Everything else is hardening.

Set the bucket to allPrivate. In the Backblaze B2 console, open the bucket settings and change the type from allPublic to allPrivate; via the CLI, the bucket name and type are positional arguments:

b2 update-bucket <bucket-name> allPrivate
# v4 CLI: b2 bucket update <bucket-name> allPrivate

The change takes effect immediately: existing files stop being anonymously downloadable. Because the type is mutable, you can flip this control the moment you find an exposure; it is not baked in at creation.

Once the bucket is private, choose how legitimate consumers reach it. The two options pull in opposite directions:

  • Serving files to end users? Use b2_get_download_authorization to mint a short-lived token scoped to a bucket prefix and expiry, generated server-side per request. Callers get temporary access to specific paths without the bucket ever being public.
  • Fronting B2 with the Cloudflare free-egress model? Keep the bucket allPrivate and put a Cloudflare Worker in front as the origin proxy. The Worker holds a B2 application key as a Worker secret, authenticates on the CDN's behalf, and returns the file, preserving the free B2-to-Cloudflare egress while the origin stays unreachable directly.

Then tighten the keys. Any application key distributed in client-side code should carry only writeFiles on the specific prefix it uploads to. Never listFiles, which is what lets a leaked key enumerate the bucket.

If the bucket was public, act on the assumption it was read. Treat every object as potentially harvested: rotate any credentials, tokens, or secrets found in exposed files, and assess disclosure and privacy obligations for any personal data that was reachable. Be realistic about forensics. B2 has no native per-object access log in the console, so you generally cannot reconstruct who downloaded what. If a CDN like Cloudflare fronted the bucket, its request logs are your best (and often only) record of the exposure window.


For an index of exposed B2 buckets found by this service, see the Backblaze B2 exposure index. To probe a specific bucket or file URL right now, use the open-bucket viewer.