RoseHacks
RoseHacks

You're in the butter zone now, baby

Password Reset Poisoning

Password Reset Poisoning

Poisoning Password Reset Links

One of my favorite bugs to hunt for has been password reset poisoning. Why? Well, first off, it’s a fun and relatively straightforward bug to test for. And second, platforms usually pay decently for it, so the effort-to-reward ratio is pretty satisfying.

But why is allowing aribtrary host headers (which is the first step to identifying password reset poisoning) so common in applications? Let’s break down some reasons:

Authentication Required

Lack of Proper Host Header Validation
  • Many web servers (e.g., Apache, Nginx) and frameworks (e.g., Flask, Express.js) do not strictly validate the Host header by default.
  • Developers often overlook implementing strict validation or allowlisting of valid Host headers, leading to trust being placed in user-supplied headers.
Reverse Proxy Misconfigurations
  • When reverse proxies are used (e.g., Nginx or HAProxy), misconfigurations may allow arbitrary Host headers to be passed upstream to the application.
  • Many proxies don’t sanitize the Host header by default unless explicitly configured.
Use of Development/Test Configurations in Production
  • During development, it’s common to run applications with permissive configurations (e.g., allowing all Host headers with 0.0.0.0 or *). If these configurations are carried over to production, the application remains exposed.
  • Misuse of Framework Defaults
Some web frameworks trust the Host header as-is to build URLs
  • Django’s default ALLOWED_HOSTS setting is empty in development (ALLOWED_HOSTS = [‘*’]), allowing all Host headers unless explicitly configured.

As you can see, there are many ways an application may end up configured in this way. Once I’ve identified that an application allows arbitrary host headers, the next step is to determine if it can be exploited. This can be achieved in several scenarios, such as cache poisoning or password reset poisoning. For more details, check out PortSwigger’s guide to Host Header Attacks here.

Abusing The Logic in Password Reset Features

Once we discover an application that allows arbtrary host headers, and we have the ability to test this feature (we can create and use accounts), its time to test for the bug.

  1. Dicover a way to get the application to allow arbitrary host headers. Sometimes there may be some sort of validation on the value of the host header. I’ve had success trying things like:
Host: example.com
Host: example.commmmmmm.attacker.com
Host: attacker.example.us
Host: example.attacker.com


  1. Using our proxy, capture a request to to reset our user’s password.
  2. Change the Host header to an arbitrary value and forward the request.
  3. Check you email and hope for the best!

Good Luck and Happy Hunting!

References

  • https://portswigger.net/web-security/host-header
  • https://portswigger.net/web-security/host-header/exploiting/password-reset-poisoning
  • https://www.invicti.com/learn/password-reset-poisoning/