Yes, it can happen. Any tool that fetches a link with GET, such as a prefetcher or a crawler, can trigger an action your page performs on GET. Design one-time links so GET only shows a confirmation page, and the state change happens on a POST that a person submits.
Definition
A one-time link is a URL in an email that carries a single-use token, for example for a password reset, email confirmation or passwordless sign-in. HTTP defines GET as a safe method. RFC 9110 says safe methods are essentially read-only: the client does not request, and does not expect, a state change on the server.
The same RFC explains why this matters. It says the purpose of separating safe and unsafe methods is to let automated retrieval (spiders) and pre-fetching work without fear of causing harm. It also says that when a URL's parameters select an action, the resource owner must make sure the action matches the method, and must disable an unsafe action when it is reached with a safe method.
What goes wrong in practice
If your reset link consumes the token on GET, then anything that fetches it before the user does can invalidate it. Some mail setups and security tools open links for checking. Whether that happens to you depends on your recipients, so treat it as something to test rather than assume. Support tickets that say "the link says it has expired but I just got it" are the usual symptom.
There is a second risk. If GET both consumes the token and logs the user in, an automated fetch could in some designs complete sign-in. The fix is the same.
A safer design
| Step | GET request | POST request |
|---|---|---|
| Open link | Validate token exists and is unexpired, show a page with a button | Not used |
| Confirm | Do not change state | Consume token, set session or password |
| Token checks | Read-only lookup | Re-check token, single use, expiry |
Guidance for reset flows adds the rest. Generate tokens with a cryptographically secure generator, make them long enough to resist brute force, tie each to one account, and make them single use with a sensible expiry. Send the reset page with a no-referrer policy so the token does not leak in the Referer header to other resources.
Steps
- Find every email link that carries a token and note what a plain GET does.
- Move the state change behind a POST with the token in the body or a form field.
- Keep the token valid after a read-only GET, and invalidate it on success or expiry.
- Add a no-referrer policy and avoid third-party scripts on the page.
- Log the user agent and result for each token use, so you can see non-human fetches.
- Test by fetching the link with a command line client, and confirm the token still works afterward.
Where Safeguard fits
Safeguard's web application scanning (DAST) can exercise endpoints like these and help flag state changes behind GET. Try the free scan at https://gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
Is a longer token enough to fix this?
No. Length helps against guessing. It does nothing about a tool that legitimately holds the link and fetches it.
Should a reset token survive a GET?
Yes. A read-only GET should not consume it. Consume it on the POST that sets the new password.
Sources
Last reviewed: 19 October 2026.