Wi-Fi QR Codes: What They Actually Contain, and What Most Generators Get Wrong

The Wi-Fi QR code taped to the wall in a café is doing something more literal than most people assume. It is not granting access. It is not authenticating anything. It is a sign with your password written on it, in a typeface humans happen not to read.

That is worth understanding before you print one, and the format itself is worth understanding if you generate them — because a surprising number of tools produce codes that are technically invalid and only work because scanners are forgiving.

The format, in full

A Wi-Fi QR code contains a short text string. That is all a QR code ever holds; the “Wi-Fi” part is a convention about how the text is shaped. Scan one with a plain text scanner and you will see something like:

WIFI:T:WPA;S:CoffeeHouse;P:flatwhite2024;;

Broken apart:

FieldMeaning
WIFI:Prefix that tells the scanner what this is
T:Security type — WPA, WEP, or nopass for an open network
S:SSID, the network name
P:Password, in plain text
H:Optional, true if the network is hidden
R:Optional, transition-disable value for WPA3
;;Terminator

Your password is in there as readable characters. No hashing, no encryption, no key exchange. Anyone who photographs that sign has it, and any scanning app on the phone has it too, along with whatever that app chooses to do with what it scans.

This is not a flaw in the design. It was always intended as a convenience for sharing a password you were willing to share. It becomes a problem when people treat the QR code as though it were an access-control mechanism, and print one for a network that also reaches the till system.

The escaping problem

Look at the format again. Semicolons separate the fields. Colons separate names from values. So what happens when your password contains a semicolon?

It breaks. The parser reads the semicolon as the end of the password field and everything after it becomes garbage.

The convention that emerged — from ZXing, the open-source barcode library that most implementations descend from — is to escape special characters with a backslash. Four characters need it: \ ; , : and, by some readings, ".

A network called Guest; Wi-Fi with the password p@ss:word should be encoded as:

WIFI:T:WPA;S:Guest\; Wi-Fi;P:p@ss\:word;;

That is exactly what our generator produces, and we verified it by decoding the finished image back to a string and comparing character by character rather than trusting that the encoder had done what we asked.

This matters more than it sounds. Passwords with punctuation are the good ones. A generator that silently drops or mangles a semicolon produces a QR code that looks perfect, scans cleanly, and joins the wrong network — or no network — with an error message that blames the password.

Test any generator you rely on by giving it a password containing ; and : and scanning the result. Plenty fail.

The WPA3 mess

Here the picture gets genuinely messy, and it is worth knowing if you are setting up a modern network.

WPA3 uses an authentication method called SAE. Reasonably enough, several major platforms decided that a WPA3 network should therefore be encoded as T:SAE.

The WPA3 specification says otherwise. It states that where the type field is present, its value is set to WPA — because the field describes that there is a password, not which handshake is used. SAE is not a valid value.

As one detailed survey of real-world generators found, Android, KDE Plasma and GNOME all emit the non-compliant T:SAE. Windows is among the few producing spec-compliant output.

There is a second incompatibility layered on top. The WPA3 specification calls for percent-encoding of special characters. Android uses backslash escaping — the older ZXing convention described above — and Android’s own scanners do not understand percent-encoding. So a generator that follows the specification precisely produces codes that fail on a large share of the world’s phones, while a generator that follows the older convention produces codes that are technically invalid and work almost everywhere.

We chose the older convention, deliberately, because a QR code that scans is worth more than a QR code that is correct on paper. It is a compromise and we would rather name it than pretend the question does not exist.

The R: transition-disable field is the third casualty. Networks running WPA3-only are supposed to include it; most generators omit it entirely.

What you are handing over

Three things worth thinking about before printing one.

The password is permanent until you change it. A sign on a wall is photographed, posted, and indexed. Guest network passwords shared this way should be treated as public from the moment they are printed, and rotated on a schedule.

The scanning app sees it. When you scan a Wi-Fi QR code, the decoded string passes through whichever app did the scanning. A camera app built into the operating system handles it locally. A third-party scanner downloaded from an app store makes its own choices, and some of those apps log what they scan to a server. This is a good reason to use the built-in camera rather than a scanner app for anything sensitive.

A QR code can be replaced. The most effective attack on a Wi-Fi QR code is a printed sticker placed over the original, pointing at a network with the same name and an attacker’s equipment behind it. Nothing about the format prevents this — there is no signature, no origin, nothing to verify. A code on a laminated card behind a counter is meaningfully safer than one taped to a window.

Read one before you trust it

Because a Wi-Fi QR code is just text, you can inspect one before letting your phone act on it — and this is a genuinely useful habit for any code in a public place.

Most phone cameras, on recognising a Wi-Fi code, offer to join the network directly. That is the convenient path and it hides the payload from you. Instead, scan the code with any plain text QR reader, or with the camera’s raw-text mode where one exists. You will get the string itself:

WIFI:T:WPA;S:CoffeeHouse;P:flatwhite2024;;

Now you can see the network name before joining, rather than after. If the SSID is not what the sign in front of you claims, or the security type is nopass when you were told the network was protected, you have learned something useful for free.

This is also the fastest way to test a code you have generated yourself. Decode it back to text and read it. If the escaping is wrong, you will see it immediately — a password that ends early, or stray characters where a semicolon should have been. It is the check we run in our own build, and it takes a phone and five seconds to do by hand.

If you are setting one up

  • Put guests on a separate network from anything that matters. This is the single most useful step and it makes the rest of these concerns much smaller.
  • Use nopass correctly if the network is genuinely open — do not put a placeholder in the password field.
  • Test the code before printing by scanning it with both an Android and an iOS device. The compatibility gaps above are real and they do not show up until you try.
  • If your password contains punctuation, verify the escaping specifically. Do not assume.
  • Regenerate whenever the password changes, and remove old printed copies.

Build a Wi-Fi, contact card, email or SMS QR code in your browser with our QR generator. Nothing is uploaded, and the escaping is verified by decoding the finished image back.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top