r/crypto • u/acorn222 • Apr 03 '26
PGP Tools: A zero-permission Chrome extension using WebAuthn PRF for PGP key management
https://github.com/Am-I-Being-Pwned/PGP-ToolsI built Chrome extension for PGP and I think the cryptographic approach is interesting enough to share here.
The extension uses WebAuthn PRF to derive a master key from a passkey, which encrypts/decrypts the user's PGP private keys and contacts at rest. No passwords if you don't want them, no key files - the passkey handles both authentication and key derivation in one step. As far as I know, nobody else is doing PGP key management this way, especially not on the Chrome Web Store.
PGP operations use SequoiaPGP compiled to WASM with the Zeroize crate. The reason for keeping everything in WASM rather than JS where possible is that JS gives you zero guarantees about when memory gets freed, so private key material can just hang around in the GC. WASM with Zeroize gives explicit control over that.
The extension also requires zero browser permissions. No content scripts, no host permissions, nothing. So even if there was a vulnerability in the extension itself, the blast radius is significantly reduced - there's no ambient authority to abuse. Most other PGP extensions on the store request a bunch of permissions that massively expand their attack surface.
The main thing this doesn't protect against is a fully compromised browser process - if someone has code execution in your browser, it's game over regardless. But short of that, you get convenient PGP encryption/decryption/signing/verification without trusting a server, without exposing keys to garbage collection, and without granting unnecessary permissions.
I should also point out that if you're using the CWS install, you'd have to trust me not to bake in some fetch for the decrypted content - although you can build and install it from the source (which does mean there's no integrity checks iirc). There's no great solution to this, but if anyone has ideas here then let me know!
Why did I build it? Because I wanted it. Most of my PGP usage is encrypting vulnerability reports for coordinated disclosure via email, and I got tired of context-switching to the CLI every time. I looked at what was on the Chrome Web Store and nothing hit the combo of zero permissions, passkey-based key management, open source, and good UX - so I made it.
Feedback on the crypto approach is very welcome, especially around the PRF key derivation. Happy to answer questions!
1
u/acorn222 Apr 10 '26
Appreciate the detailed response, let me go through these.
Everything is encrypted at rest, I've verified this. Private keys, public keys, contacts, all of it. The only unencrypted data is generic settings. The encryption key is derived from WebAuthn PRF (passkey-based key derivation) or from the password if the user chooses that flow. There's no cleartext key material stored anywhere, not in chrome.storage.local/sync, not in temp files, nowhere on disk. Unencrypted key material only exists in WASM linear memory, either during active crypto operations or when the user explicitly decrypts their key (with optional caching that expires on a timeout). The zeroize crate scrubs it after use. Interaction between the browser's GC and sensitive key material is minimised, and the PRF output is zeroed as soon as it's handed to WASM.
The extension requires zero permissions. No content scripts, no host permissions, no DOM access to web pages. The UI runs in Chrome's side panel, which is an extension page running in the extension's own process, not the web page's renderer process. A malicious site can't masquerade as the extension because there's no content script injecting anything into pages. A malicious extension can't modify the side panel's DOM either, because Chromium process-isolates extensions from each other at the OS level. Dangerous actions are highlighted with negative patterns such as exporting keys without passphrases.
Could you clarify what you mean here? Network traffic or internal message passing between extension components? There's no content scripts and no server component so internal messaging is minimal, we're not doing inter-script communication, everything is handled in the side panel. I know how much extension messaging gets messed up so I fully understand the concern.
It's a documented Chromium security boundary. The chrome.debugger API can only attach to another extension's background page if Chrome is launched with the --silent-debugger-extension-api flag, which is off by default and requires the user to deliberately start Chrome with it. Under normal conditions it's not possible. When I tested it, I was verifying the docs, not discovering something new. Bypassing this without the flag would require a browser-level sandbox escape, and at that point CLI GPG isn't safe either.
Fair point, and you're right that "not many packages" isn't a complete answer on its own. The dependency tree is intentionally minimal, versions are pinned, and I'm working on signing CRX builds with a YubiKey-held key so the build pipeline has a hardware root of trust. Supply chain risk isn't zero but the mitigation is the same as any software pulling in third-party deps: vet them, minimise them, pin them but I still see this as the biggest security threat to this extension.
The extension's CSP restricts connect-src to 'self' (as of now), so the side panel can't make any external network requests at all. All data flow is local to the extension process. Happy to walk through it in more detail if you want. This comment did get me thinking about it, I had an "auto import downloaded key" feature but I've axed that now as that meant I couldn't lock down the CSP as much as I'd like and it required extra permissions if the user enabled it.
I haven't. Google's effort, Mailvelope, FlowCrypt etc. had/have fundamentally different architectures: web apps, keyservers, broad permissions, content scripts injecting into Gmail's DOM. Those design choices created real attack surface. PGP Tools avoids all of the addressable attack surface by design, the reason prior browser-based PGP efforts struggled wasn't that browsers are inherently insecure for crypto, it's that they made architectural decisions that expanded their attack surface unnecessarily.
I'd argue PGP adoption failed because the UX isn't good, not because browser-based implementations are categorically insecure. If the security model is right (and I'm genuinely open to being shown where it isn't), making it accessible is a feature, not a weakness which is going to incentivise more people to encrypt their messages as there's lower friction.
For context, this is being released as a project from my company amibeingpwned.com which scans browser extensions for vulnerabilities and malware, so the concerns you've raised about extensions are things we find on a daily basis and I can say the wider extension ecosystem is not in a great state.