Security and verifiability

This page describes what technically happens when you generate a password on pwgen.de — and above all how you can check it yourself instead of taking our word for it. Where a claim is currently not verifiable, it is stated at the end of this page.

Generated in your browser

Passwords, passphrases, PINs, tokens, patterns and framework secrets are created on your device. There is no step in which a generated value is sent to a server — not to rate its strength, not to count anything.

Every character comes from crypto.getRandomValues(), the browser's cryptographically secure random source. Selection uses rejection sampling: random values that would not map evenly onto the character set are discarded rather than folded in with a modulo. Every character of the chosen set is therefore exactly equally likely. Math.random() appears nowhere.

  • Passphrases draw from complete Diceware lists of 7,776 words each (German and English), loaded from the same domain.
  • The site sets no cookies. The only value stored locally is the acknowledgement of the privacy notice in localStorage.
  • Generated values are never written to the page URL, to a form, or to any history.

What the browser is allowed to do

A Content Security Policy is stronger than a promise: the browser enforces it, not us. The decisive directive is connect-src 'self'. It permits network connections to this domain only. Even if injected code tried to send a generated password somewhere, there would be no permitted destination for it.

In addition, frame-ancestors 'none' forbids embedding the site in foreign frames, object-src 'none' blocks plugin content, base-uri 'none' prevents an injected <base> element, and form-action 'self' stops forms from submitting elsewhere. Images are limited to this domain and data: URIs, fonts to this domain.

One limitation stays on the record: script-src contains 'unsafe-inline'. Nuxt writes its hydration state into the page as an inline script, and because nearly every page is prerendered, the HTML exists long before a request is seen — a per-response nonce is therefore not possible. That weakens protection against injected script, but not against data leaving: connect-src applies regardless.

Content Security Policy as served

default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'

Check it yourself

curl -sI https://pwgen.de/ | grep -i content-security-policy

Local generator and REST API

There is exactly one place where a value is created on the server: an explicit call to /api/generate. Using the API is a deliberate choice — the website itself never calls it.

Nothing is logged there either. The server has no logging path that receives a generated value, and every response carries no-store. If you want maximum control, use the generator in the browser: the value then never leaves your device.

  • The API is open, needs no authentication and is language-neutral; errors consist of stable codes rather than text.
  • Each IP address is limited to 60 requests per minute. The limit protects the service, not your data — it is the only reason the server holds IP addresses in memory briefly.
  • CORS is deliberately open (*) so that the widget also works on third-party sites.

Widget on third-party sites

The embeddable widget is a standalone file without dependencies. It also generates in the visitor's browser, uses the same random source with rejection sampling, and only loads the wordlists from pwgen.de. It transmits no generated values and sets no cookies.

Analytics

Reach is measured with a self-hosted Umami instance that uses no cookies. It is not even loaded on the pages that generate secrets: neither on the homepage nor on the generator and secret pages nor in the widget. Only guides, API documentation, legal texts and this page are counted.

You can check this in the network tab: on a generator page there is no request for an analytics script. What is collected on the remaining pages is described in the privacy policy.

Reporting a vulnerability

If you notice something, please report it directly — ideally with steps to reproduce and the endpoint concerned. We confirm receipt, investigate and come back to you with the next steps. Please hold off on publishing a finding until it is fixed or we fail to respond.

Security reports

info@htrs.io

Machine-readable at /.well-known/security.txt

What this page does not prove

Everything described above can be observed in the browser: network tab, source of the delivered scripts, response headers. What that does not show you is the build process behind it.

The source code of pwgen.de is currently not public, and no independent audit report exists. Until that changes: you can verify what is delivered, but you cannot independently confirm that the delivered code was built from a source tree you can inspect. We would rather state that limitation here than leave it out.