Trust, verified
How Our Password Generator Works: Verify It Yourself
Don't trust us - verify it. Every generator and checker on this site runs entirely in your browser. Here is exactly how, and four ways to check it in under two minutes.
What Happens When You Click Generate
- The page asks your browser for random numbers through
crypto.getRandomValues(), the Web Crypto API. It returns cryptographically strong random values from a generator that the specification recommends seeding from the operating system's entropy source. - Each character, word or digit is chosen with rejection sampling: random 32-bit values that would make some choices slightly more likely than others are thrown away and redrawn. The result is exactly uniform.
- If you require each character type, a whole candidate password is drawn and rejected if a type is missing. No character type is ever placed in a fixed position, and every valid password is exactly as likely as any other.
- The password is written into the page. That is the end of its journey: no request is made, nothing is written to cookies, localStorage or any other storage, nothing goes into the address bar, and the password is never logged.
If the Web Crypto API is unavailable, the generator refuses to run. There is no fallback to Math.random(), which is not designed for security. This is the code that does it, taken from the module at build time:
function getRandomValues(): <T extends Uint8Array | Uint32Array>(array: T) => T { const source = globalThis.crypto; if (typeof source?.getRandomValues !== 'function') { throw new Error('Secure random numbers are unavailable: crypto.getRandomValues() is missing.'); } return (array) => source.getRandomValues(array);} /** * Returns `count` independent integers in [0, maxExclusive), every value exactly equally likely. * * Rejection sampling: 32-bit draws at or above the largest multiple of maxExclusive are * discarded and redrawn, so `value % maxExclusive` carries no modulo bias. Values are drawn * in batches (one CSPRNG call per batch rather than per value) for speed. */export function randomInts(maxExclusive: number, count: number): number[] { if (!Number.isInteger(maxExclusive) || maxExclusive < 1 || maxExclusive > RANGE) { throw new RangeError(`maxExclusive must be an integer in [1, 2^32], got ${maxExclusive}`); } if (!Number.isInteger(count) || count < 0) { throw new RangeError(`count must be a non-negative integer, got ${count}`); } const fill = getRandomValues(); const limit = RANGE - (RANGE % maxExclusive); const buffer = new Uint32Array(Math.min(count, MAX_DRAWS_PER_CALL)); const result: number[] = []; while (result.length < count) { const draws = buffer.subarray(0, Math.min(count - result.length, MAX_DRAWS_PER_CALL)); fill(draws); for (const value of draws) if (value < limit) result.push(value % maxExclusive); } return result;}The complete generation module is 11 small files (1020 lines including comments) with no dependencies. The same code powers the password generator, the passphrase generator, the PIN generator and the random values of the developer tools.
Four Ways to Verify It Yourself
1. The offline test
Open the password generator, then disconnect from the internet: switch off Wi-Fi or enable airplane mode. Keep clicking regenerate, change the length, download a bulk file. Everything still works, because nothing needs a server. The passphrase generator loads its wordlist when the page opens and the strength checker loads its dictionaries when you first click into its field - both from this domain; after that they work offline too.
2. The network tab
Open your browser's developer tools (F12, or Cmd+Option+I on a Mac) and select the Network tab. Reload the page: you will see only files from this domain - the page, stylesheets, fonts, scripts. Now generate, copy and download as much as you like. No new request appears. Do the same on the password strength checker while typing a password.
3. The source
The readable source of the generation module is published with every build: encoding.ts, entropy.ts, keys.ts, md5.ts, otp.ts, passphrase.ts, password.ts, pin.ts, random-string.ts, random.ts, uuid.ts. Every tool takes its randomness from random.ts and nothing else. The page itself runs a minified bundle compiled from these files - smaller to download, same logic. Comparing the two takes some expertise: we do not offer reproducible builds yet.
4. The Content Security Policy
In the developer tools, open the response headers of any page and find the Content-Security-Policy. It is:
default-src 'self';
script-src 'self' https://www.googletagmanager.com 'sha256-…';
style-src 'self';
img-src 'self' data: https://www.google-analytics.com https://*.google-analytics.com;
font-src 'self';
connect-src 'self' https://www.google-analytics.com https://*.google-analytics.com https://*.analytics.google.com;
worker-src 'self';
object-src 'none';
frame-ancestors 'none';
base-uri 'self';
form-action 'none'The 'sha256-…' values are the fingerprints of the few small inline scripts the page framework writes into each page. The browser runs an inline script only if its fingerprint matches exactly, so an inline script injected into the page cannot run.
Why the Content Security Policy Matters
A promise that "we don't send your password anywhere" is only as good as the code on the page, and pages commonly load dozens of third-party scripts: analytics, ads, A/B testing, chat widgets, session-replay tools that record keystrokes. Any one of them could read a password field. The Content Security Policy is the browser-enforced rule that stops that from being possible here:
script-src 'self'plus fingerprints - the browser only runs scripts from this domain, the exact inline scripts we ship, and the three named analytics providers. No other third-party script can execute.connect-src 'self', plus the analytics providers' own endpoints - scripts cannot usefetch, XHR, WebSockets or beacons to send data anywhere else.form-action 'none'- no form on the site can submit anywhere.frame-ancestors 'none'- no other site can embed these pages in a frame to overlay or spy on them.
This means the only analytics that can load is Google Analytics - no other third-party scripts, ads or tracking pixels can run at all. Fonts, wordlists and dictionaries are self-hosted for the same reason.
Clipboard Auto-Clear
When you copy a generated password, a 30-second countdown starts and the clipboard is then overwritten with an empty value. That limits how long other apps and websites can read it. Three honest caveats: the browser only allows the overwrite while the tab is focused (you will see a message if it could not clear); if you copy something else on the page during the countdown, we stop, so we never wipe your own copy; and clipboard-history features in some operating systems and apps keep their own copy. On Windows, check Clipboard history settings; on macOS, check any clipboard manager you have installed.
What We Cannot Protect Against
Client-side generation removes the server from the picture. It cannot make an unsafe device safe:
- Malware or a malicious browser extension can read any page, including this one. Extensions with "read and change all your data on all websites" permission deserve scrutiny.
- Someone looking at your screen. The strength checker hides your input - and the breakdown of it - by default for this reason.
- Where you store the password afterwards. Use a reputable password manager.
For the maths behind the strength numbers, see the password entropy calculator.
Trust & Privacy FAQs
Are online password generators safe?
A generator is safe when it runs on your device, uses a cryptographically secure random source and makes no network requests - and when you can check all three. This site is built so you can: go offline, watch the network tab, read the source, inspect the Content Security Policy.
Do you use analytics or cookies?
Yes - the site uses Google Analytics to measure page usage, and it sets cookies. It only ever sees which pages are visited, never what you generate or type, and the Content Security Policy blocks every third-party script except Google's. You can opt out with your browser's settings or an analytics-blocking extension; the tools keep working either way.
Where is the password generated?
In your browser tab, using crypto.getRandomValues(). Bulk batches run in a Web Worker - a background thread of the same page, loaded from this site. Our server only delivers static files; it never generates, receives or stores a password.
Is crypto.getRandomValues() secure?
Yes. It returns cryptographically strong random values. The W3C Web Cryptography API specifies it, and recommends that browsers use a well-established cryptographic generator seeded from the operating system's entropy source. Every modern browser implements it.
Why not use Math.random()?
Math.random() is a fast pseudo-random generator for simulations and games. Its output can be predictable, and it is not intended for secrets. Our generator refuses to run if the secure API is missing rather than fall back to it.
Can I read the source code?
Yes. The readable source of the generation module is published on this site under /source/crypto/, rebuilt with every release, and a test checks that it matches our repository. There is no public repository or open-source licence yet. The page runs a minified bundle built from these files; you cannot currently rebuild it yourself and compare.
Can I use the site offline?
Yes. Once a page has loaded, its tool keeps working without a connection. The passphrase generator fetches its wordlist from this domain when the page opens, and the strength checker fetches its dictionaries when you first click into the field; after that, both work offline too.
What data does the server see?
Standard web server access logs kept by the hosting provider: which page or file was requested, when, and from which IP address and browser. It never sees anything you generate, type or copy, because none of it is ever sent.
Related tools
