Skip to content

Automate the browser trust step so nobody types certutil - #5

Merged
ralyodio merged 1 commit into
mainfrom
trust-installer
Aug 1, 2026
Merged

Automate the browser trust step so nobody types certutil#5
ralyodio merged 1 commit into
mainfrom
trust-installer

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

"we don't want to fuck with certs people don't understand that shit"

Right — and the fix isn't removing certificates (impossible for stock browsers: no extension API can validate a registry pin, which is the entire reason the local CA exists). It's removing the step. The word "certificate" now appears nowhere a user reads.

Before

The README ended with this, and a hope:

certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "Moshpit Local CA" -i ~/.moshpit/ca/ca.crt

After

curl -fsSL https://raw.githubusercontent.com/profullstack/moshpit-proxy/main/install.sh | sh
  Moshpit needs to add a security key to this
  computer so your browser trusts .moshpit sites.
  It only works for .moshpit and cannot affect any
  other website.

  Continue? [Y/n] y

  ✓ Chrome, Chromium and Edge
  ✓ Firefox (default-release)

  ✓ Ready. Try https://scrambled.moshpit

There is still exactly one consent moment. Installing a root into someone's trust store silently is what malware does, and "they didn't have to think about it" is not a reason to skip asking. What's removed is the jargon, not the disclosure.

What doing it by hand gets wrong, and this doesn't

Each of these is a real way the documented command half-works and looks like it succeeded:

  • Firefox keeps its own NSS database per profile on every platform, including macOS — so the security add-trusted-cert keychain command covers precisely nothing for it.
  • On current Ubuntu the default Firefox is the snap, whose profiles live under ~/snap/firefox/common/.mozilla/firefox/. The documented path covers zero browsers there. Flatpak too.
  • certutil isn't installed by default on Debian or Ubuntu. The documented command fails on a machine that does have the store it points at. Now detected up front with the exact per-distro package — and checked before the consent prompt, not after, since asking someone to agree and then failing wastes the one moment of attention this gets.
  • certutil can exit zero having written somewhere the browser won't read (a profile never launched, a locked db). Every install is read back and verified rather than assumed — reporting success while the browser still shows a warning is worse than a clean failure.
  • Profiles without a cert9.db are skipped — they've never been launched, so writing there does nothing.
  • Trust bits are C,, — server certificates only. Not CT,c,c, which would also trust the root for mail and code signing.

Idempotent: status is checked before writing, so running twice is a no-op rather than a duplicate nickname.

Also added

moshpit-trust --status (reports, changes nothing), --uninstall, and install.sh --uninstall which undoes the browser setup before removing the code. install.sh checks Node by capability rather than version string, for the same reason moshpit-transport does.

Testing

51 pass (16 new), tsc --noEmit clean under strict.

Every path and command runner is injected, so the suite asserts what certutil would have been asked to do without asking it. That matters more than usual here — a test that got this wrong would silently modify the trust store of whoever ran it, and a test suite must never be something you have to undo afterwards.

The one real-certutil test creates a throwaway NSS database and round-trips add/verify/remove. It skips when certutil is absent, which is the common case — and it did not execute on my machine. Worth running somewhere with libnss3-tools installed before this merges.

Not fixed by this

Worth stating plainly: this does not fix https://scrambled.eggs/ giving an invalid certificate today. That failure is a name mismatch — pit.moshcode.sh:443 answers SNI scrambled.eggs with Railway's CN=*.up.railway.app cert, because the ssl_preread gateway in nginx/moshpit-gateway.conf isn't deployed and can't be deployed on Railway. No trust store fixes a name mismatch. Separate problem.

🤖 Generated with Claude Code

The adoption barrier was never that people distrust a locally-generated
root — it is that the README ended with

  certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "Moshpit Local CA" ...

and a hope. Certificates cannot leave the stock-browser path (no extension
API can validate a registry pin, which is the whole reason the CA exists),
but the ceremony can.

Adds `moshpit-trust` and an install.sh. The word "certificate" appears
nowhere a user reads. There is still exactly one consent moment, in plain
language — installing a root silently is what malware does, and "they
didn't have to think about it" is not a reason to skip asking.

What doing it by hand tends to get wrong, and this does not:

- Firefox keeps its own NSS database per profile on every platform,
  including macOS, so the keychain command covers nothing for it.
- On current Ubuntu the default Firefox is the snap, whose profiles live
  under ~/snap/... — the documented path silently covers zero browsers.
- certutil is not installed by default on Debian or Ubuntu, so the
  documented command fails on a machine that has the store it points at.
  Detected up front with the exact per-distro package, before the consent
  prompt rather than after it.
- certutil can exit zero having written where the browser will not read,
  so every install is read back and verified rather than assumed.

Idempotent: status is checked before writing, and running twice is a no-op.

51 tests pass (16 new), tsc --noEmit clean under strict. Every path and
command runner is injected, so the suite asserts what certutil would have
been asked to do without asking it — a test here must never modify the
trust store of whoever runs it. The one real-certutil test skips cleanly
when the tool is absent, which is the common case; it did not execute on
this machine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio marked this pull request as ready for review August 1, 2026 17:48
@ralyodio
ralyodio merged commit a8ea1d7 into main Aug 1, 2026
3 checks passed
@ralyodio
ralyodio deleted the trust-installer branch August 1, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant