Remove wildcard ALLOWED_HOSTS default to prevent password reset poisoning - #345
Merged
Merged
Conversation
The default ALLOWED_HOSTS="*" disabled Django's Host header validation, allowing an attacker to submit a password reset request with a spoofed Host header. django-allauth builds the reset URL via request.build_absolute_uri(), so the email sent to the victim contained a link to the attacker's domain with a valid reset token. Clicking it (or automated link-preview scanning) leaked the token to the attacker. With ALLOWED_HOSTS properly restricted, Django rejects spoofed Host headers with a 400 before any view runs, making request.get_host() inherently safe. - settings.py: default to localhost,127.0.0.1 instead of *. Use `or` instead of getenv's default arg so an empty-string env var (as shipped in the k8s template) falls through correctly. - Dockerfile: give the healthcheck a matching shell fallback so it still passes when the env var is unset. - app.json: Heroku one-click deploys now default to .herokuapp.com (subdomain wildcard) instead of *. - kubernetes/secrets_template.yml, GUIDE.md: remove the * suggestion and document why it's dangerous.
…wildcard .herokuapp.com is still too broad: anyone can register a Heroku app at evil.herokuapp.com. Making it required forces the one-click deploy flow to prompt the user for their actual app domain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a Host header injection vulnerability in the password reset flow. The default
ALLOWED_HOSTS = "*"disabled Django's Host header validation, allowing an unauthenticated attacker to poison password reset emails with links to their own domain — capturing valid reset tokens when victims (or email link-preview scanners) click them.Root cause
django-allauthbuilds the{{ password_reset_url }}in reset emails usingrequest.build_absolute_uri(), which derives the hostname from theHostheader. Django'sALLOWED_HOSTSsetting is the security boundary that validates this header — but"*"disables it entirely.Attack:
curl -X POST http://<shynet-ip>/accounts/password/reset/ -H "Host: attacker.com" -d "email=admin@..."→ admin receives an email linking tohttp://attacker.com/accounts/password/reset/key/<valid-token>/.Fix
Change the default to
localhost,127.0.0.1. WithALLOWED_HOSTSproperly restricted, Django'sCommonMiddlewarerejects spoofed Host headers with a 400 before any view runs — makingrequest.get_host()inherently safe downstream.settings.py*→localhost,127.0.0.1. Usesorinstead ofgetenv's default arg so an empty-string env var falls through correctly.Dockerfileapp.jsonkubernetes/secrets_template.yml*placeholder.GUIDE.md*.Upgrade note
Existing deployments that did not set
ALLOWED_HOSTSwill need to set it after upgrading. TEMPLATE.env already documented the correct value.