When you check out of an online store as a guest, using just your email, you’d expect your account to remain untouched until the next time you log in. That’s how accounts are set up to work.
But if that site has an account takeover vulnerability, bad actors can hijack your address and payment information in a few simple steps.
This is a well-known attack. It’s so simple that hackers can automate it, pre-registering thousands of emails with a malicious script. Then all they have to do is wait for people to click the familiar-looking link sent to their email.
It was an easy-to-miss vulnerability in the Saleor open source project because nothing in the code is broken. Registration, confirmation, and order merge all work as intended.
But one subtle thing is missing. Saleor never checks that the person clicking the emailed link is the same person who triggered it.
Maze Code’s agents found this vuln by reading Saleor’s codebase and reasoning over how it behaves. They followed the account flow from registration to confirmation to the order merge, where the guest data changes hands.
In this blog, we’ll walk through the bug, how to tell if you’re affected, and provide the fix.
Credit to the Saleor team for being an absolute pleasure to work with. They were responsive, transparent, and a fix shipped in versions 3.21.67, 3.22.63, 3.23.22, or 3.24.
How the bug works
Saleor is an open-source commerce platform that runs behind a lot of online stores. It lets people buy as guests, then later add those orders to a newly created account by registering with the same email address.
But when an attacker registers with the victim’s email and their own password, Saleor sends an email with a routine-looking confirmation link. The link looks innocuous, so it’s easy to click without a second thought. For users who clicked it, every guest order and gift card tied to their address moves to the hacker’s account, along with the names, addresses, and payment methods on them.
Registration is a public GraphQL mutation called accountRegister. Anyone can call it, with any email and a password they choose. So an attacker registers with the victim’s email and their own password. The account sits unconfirmed, and Saleor emails a confirmation link to the address, which lands in the victim’s real inbox.
If the victim clicks the link, confirmAccount validates the token and activates the account. On activation, it rebinds the guest data without asking anything else:
def perform_mutation(cls, _root, info, /, **data):
user = cls._get_user_or_invalid(data["email"], data["token"])
user.is_confirmed = True
user.save(...)
match_orders_with_new_user(user) # every guest order for this email
assign_user_gift_cards(user) # every gift card tagged with this email
Nothing here checks that the person confirming is the person who registered. The attacker set the password, so the account is theirs, and now the victim’s order history and gift card balances are too.
There’s no skill or race involved. Two ordinary requests, no login required, and a guest email quietly becomes someone else’s full account.
The attacker doesn’t even need a specific target. They can pre-register a whole list of email addresses at once, and a leaked list works fine for this. Then they wait. Every recipient who clicks the routine-looking verification mail hands over their account. Even a small share clicking turns one script into a stack of takeovers, each with real order history and spendable gift cards attached.
How Maze Code found it
The merge code is correct. match_orders_with_new_user does what its name says, and so does the gift card call. There’s no tainted input flowing into a dangerous function, no injection, no unsafe call. A scanner that matches patterns of known-bad code has nothing to catch here, because none of this code is bad on its own.
The bug is a check that should exist and doesn’t. You only see it’s missing if you understand what account confirmation is supposed to prove. Clicking an emailed link proves someone can reach the inbox, nothing more. Saleor’s link says nothing about whether the person clicking is the one who created the account. That ambiguity is what makes it exploitable.
Saleor treats being able to click the link as proof that you own the account, and those aren’t the same thing. You only see the problem when you connect three steps sitting in different files. Registration lets anyone set the password. Confirmation activates on inbox access alone. The merge then hands over data on the strength of that.
Maze’s agents reasoned across that whole chain and reached the account flow on their own. No one pointed them at it. Grading whether a business rule holds needs reasoning about what the code is meant to guarantee, and that is where Maze’s AI-SAST works. It reads for intent. A pattern matcher only sees syntax.
Am I affected?
You’re affected if you’re running Saleor version 3.21.66, 3.22.62, 3.23.21, or earlier with account confirmation by email enabled, which is the default, and you use guest checkout or gift cards tagged by email. Most Saleor stores are self-hosted and reachable from the open internet, so the vulnerable flow is exposed by default.
You’re not affected if account confirmation by email is turned off. With no confirmation email, there’s no link for the victim to click and nothing triggers the merge.
The fix
Upgrade to a patched release. Install 3.21.67, 3.22.63, or 3.23.22. Saleor disabled automatic merging by default in those versions, and version 3.24 requires the user to confirm their password before any guest data is linked. Saleor’s account-merging documentation covers how to re-enable merging safely once your storefront prompts for the password.
If you can’t upgrade right away, require the confirming user to prove the account password before any merge, or defer the merge until a real, password-authenticated login. Either one closes the path. The password is the one thing the attacker can’t supply for the victim, because the victim never set it.
Credit to the Saleor team, who confirmed the issue and shipped the fix across every supported version. It’s tracked as CVE-2026-44472, with the affected and patched versions detailed in Saleor’s advisory, GHSA-6whj-8p3f-2xqp.
About Maze Code
Maze was built to reason, not run on rules, and delivers security that cuts through the noise to surface what’s real. Our agents investigate every vulnerability across your dependencies, code, and cloud to find and fix what matters.
Maze Code agents have found exploitable CVEs in multiple open source projects scanned by other AI-SAST tools. Learn more about Maze Code.




