Safeguard
Security Guides•

Why do Docker registry htpasswd logins fail, and what is the trap?

The registry accepts only bcrypt in htpasswd, and a missing file is silently recreated with a default user. How to create the file and verify it.

Safeguard Security Team
3 min read

Docker registry htpasswd logins usually fail because the hashes are not bcrypt. The registry supports bcrypt only and ignores other entries. A second trap is quieter: if the htpasswd file is missing, the registry creates it with a default user and a generated password.

The bcrypt rule

The configuration reference says that for auth.htpasswd, only bcrypt hashes are supported, and other entries are ignored. The deployment guide repeats it: create the file with the -B flag, because omitting it causes all authentication to fail.

The guide's example runs the htpasswd tool from a container so you do not need it installed locally.

docker run --entrypoint htpasswd httpd:2 -Bbn testuser testpassword > auth/htpasswd

Then start the registry with REGISTRY_AUTH=htpasswd, REGISTRY_AUTH_HTPASSWD_PATH and REGISTRY_AUTH_HTPASSWD_REALM. On Windows, the guide says to write the file with ASCII encoding.

Note that typing a real password on the command line leaves it in shell history. Use a throwaway value to create the file, or read the password from a prompt, and avoid the pattern in the example for real accounts.

The default user trap

The configuration docs carry a warning: if the htpasswd file is missing, the file is created and provisioned with a default user and an automatically generated password.

Think about how that goes wrong. A volume mount is misspelled, a path changes in a deploy, or a secret fails to mount. The registry starts anyway, and now it has an account nobody planned for. The password is generated and not published, so the risk is lower than a well known default. Still, you have a registry running with credentials that you did not provision and do not track.

A short checklist

  1. Generate the file with -B and check that each line starts with a bcrypt prefix such as the dollar 2y marker.
  2. Mount it read only into the container, from a secret store where you can.
  3. After every deploy, confirm an anonymous request to /v2/ returns 401.
  4. Confirm a login from the expected account works and one with the wrong password fails.
  5. Alert if the registry starts while the file is absent or empty.
  6. Review the file for accounts that no longer belong to a live person or pipeline.

Why TLS still matters

Basic auth sends the password in a header on each request. The docs say to use this scheme only with TLS. A correct bcrypt file protects the stored hash at rest. It does nothing for a password that crosses the network in clear text.

Rotating a password

Edit or regenerate the line for that user, replace the file, and reload per your deployment method. Update the secret in every pipeline that uses the account. Because each pipeline should have its own account, rotating one does not break the others.

For visibility into what your registry holds, Safeguard offers container image scanning and SBOM generation, with a free scan at gold.safeguard.sh/scan.

Quick check

Can I use an MD5 or SHA htpasswd file?

No. The configuration reference says only bcrypt hashes are supported and other entries are ignored.

How do I know the default user was not created?

Check the file after each start, test that only expected accounts can log in, and alert when the file path is missing.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.