QR codes are a security boundary most developers never think about, and attackers have noticed. The code is an opaque link: the user cannot see where it leads until it is too late. If you generate, serve, or scan codes in your product, security is your problem.
Start with the generation side. If your system creates codes from user-supplied URLs, you are one bad input away from printing a phishing link with your brand on it. Validate destinations against an allowlist or at minimum a strict URL parser — scheme, host, and path rules. Log every generation with the responsible actor, because codes are permanent physical artifacts that outlive the session that created them.
The resolution side matters just as much. A dynamic code is a redirect service, and redirect services are a classic open-redirect vulnerability if misconfigured. Never allow arbitrary destinations from unauthenticated callers. Enforce destination validation at resolution time, not just at creation time — a link that was safe when created can be repointed to malware later.
Scanning is the third surface. If your app scans codes, the scan is an untrusted input that leads to a network fetch. Treat it that way: never auto-open links, always show the destination for confirmation, and consider a reputation check on the domain before the browser loads it. Users scanning with a QR scanner that has link checking get protection the default camera app does not provide.
Finally, think about the physical layer. Sticker-swap attacks mean a code in the wild may not be yours anymore. Monitor your codes for unexpected redirect changes, and if you manage public placements, educate the owner about tampering.
The threat model is real, the mitigations are standard, and the cost of ignoring it is a phishing incident wearing your logo.
Top comments (0)