How Kit-Bin's Password Generator Actually Gets Its Randomness
"Random" is doing a lot of work in the phrase "random password generator," and not every source of randomness in JavaScript is fit for the job. There are two very different random number generators available in a browser, and using the wrong one quietly undermines the whole point of generating a password instead of typing one.
Math.random() is not built for this
Math.random() is a pseudorandom number generator: fast, deterministic under the hood, and statistically fine for things like shuffling a game board or picking a random UI animation. Deterministic is the problem. Its output is generated from an internal seed state through a fixed algorithm, and depending on the engine's specific implementation, observing enough outputs can make that internal state, and therefore all future outputs, predictable. For a game, that's irrelevant. For a password, it means the "randomness" isn't necessarily unrecoverable by someone motivated enough to try, which disqualifies it for anything security-sensitive regardless of how random the output looks statistically.
crypto.getRandomValues() pulls from the OS instead
The Web Crypto API's crypto.getRandomValues() does not generate numbers from a predictable internal algorithm the same way. It draws from the operating system's cryptographically secure random source (on most platforms fed by hardware entropy like timing jitter and other unpredictable physical noise), the same underlying source used to generate encryption keys. Its output is designed to be infeasible to predict even with full knowledge of previous outputs, which is the actual bar a password generator needs to clear.
A subtler bug: modulo bias
Getting a secure random byte is only half the job. Turning it into a character from your password's allowed set is where a second, easy-to-miss mistake shows up. A naive implementation takes a random byte (0-255) and does byte % charsetLength to pick a character index. If the charset length doesn't divide 256 evenly, which it almost never does, the low end of the charset gets selected slightly more often than the high end, because there are more byte values that wrap around to the low indices than the high ones. With a 62-character set, for example, 256 รท 62 leaves a remainder, so the remainder's worth of byte values land unevenly.
The bias is small, but it's a real, measurable statistical skew in a place where a generator is specifically supposed to produce uniform randomness. The correct fix is rejection sampling: if a byte falls in the range that would cause uneven wraparound, discard it and draw another, rather than reduce it into range unevenly. It sounds pedantic for a single password, but it's exactly the kind of shortcut that turns "generates strong passwords" into "generates passwords that are ever so slightly more predictable than advertised," at scale.
The bigger trust question: where does generation happen
Randomness quality is only part of the trust equation. A password generator that runs on a server, even one using proper cryptographic randomness, requires trusting that server never logs the password it just generated for you, before it ever reaches your browser. That's a trust assumption you can't verify from outside. Kit-Bin's Password Generator runs the entire generation process client-side, in your browser, usingcrypto.getRandomValues() directly. The password it produces is never transmitted anywhere, because there's nothing to transmit it to. The same client-side principle applies to SHA-256 hashing, another real cryptographic primitive that runs entirely in your browser rather than on a server that could log what you send it.