Security, in plain English
What we do to protect your account and the people who scan your codes, stated as facts you can check against our terms and privacy policy. No badges, no certifications we do not hold, and no uptime figure we cannot back.
Your account
- Passwords are stored only as PBKDF2-SHA256 hashes, 210,000 iterations, with a random salt per password. Older hashes are upgraded to the current work factor when you next sign in.
- Sessions use a random 32-byte token in an HttpOnly cookie. We store only its SHA-256 digest, so a copy of our database cannot be used to sign in as you. Changing your password signs out every other device.
- Password reset links work once and expire after an hour; address confirmation links expire after 48 hours. Only their digests are stored.
- Sign-in is rate limited per network and per account, and a wrong password and an unknown address get the same answer, so the form cannot be used to find out who has an account.
- New devices: a sign-in from a browser we have not seen before triggers an email to you.
- API keys are shown once and stored as a hash. Each key is read-only or read-write, and can be given an expiry date.
Payments
Checkout is hosted by Stripe. Card details are entered on Stripe's page and never reach our servers. We keep the Stripe customer identifier, your plan and your subscription status, which is what we need to know whether your codes should redirect.
The people who scan your codes
- No IP address is stored: not in the scan log, not in the sign-in audit log, and not for rate limiting, where it is hashed with a secret key first. Location comes from the network edge as country, region and city.
- Repeat visits are counted with a keyed hash of the IP address, user agent and day, which cannot be reversed and cannot link a visitor across days.
- Destinations are screened against Google Safe Browsing when a code is created or changed, and re-checked periodically. Only the destination address is sent, never anything about who scanned. A destination reported as unsafe is not forwarded to.
- Destinations are limited to web, email, phone and text links, so a code cannot point at a script.
Our pages
Our fonts are served from our own origin, and our pages load no third-party scripts, analytics tags or trackers. A content security policy tells browsers to refuse scripts from anywhere else.
Who runs it, and where
My QR Code is a service of DDR Solutions Inc., a company incorporated in Ontario, Canada, handling personal information under PIPEDA. The service runs on Cloudflare's network, with data stored in Cloudflare's database service, so it may be processed in Canada and the United States. Stripe handles payments, Resend sends account email, and Google Safe Browsing screens destination addresses. Where the in-app help assistant is switched on, the question you type is sent to Anthropic's API to answer it. The privacy policy and the data processing agreement set out what each party receives and how scan data is handled on your behalf.
What we do not claim. We hold no security certification and publish no uptime guarantee. We do not offer single sign-on or team accounts. We do not claim GDPR compliance.
Reporting a problem
If you think you have found a security issue, write to hello@my-qrcode.io with what you found and how to reproduce it.
Questions
How are passwords stored?
As PBKDF2-SHA256 hashes with 210,000 iterations and a random salt per password. The password itself is never stored.
Do you store card details?
No. Payment happens on Stripe's hosted checkout page and card details never reach our servers. We store the Stripe customer identifier, your plan and its status.
Do you store IP addresses?
No. Not for scans, not in the sign-in audit log and not for rate limiting, where the address is hashed with a secret key before it is used.
My QR Code makes dynamic QR codes for print. Fourteen days free, two codes, no card required.
Start free