Metadata-Version: 2.4
Name: certlens
Version: 1.0.0
Summary: Audit the certificate authorities your machine trusts: who runs them, which government they answer to, and which roots nobody vouches for.
Author: certlens contributors
License: MIT
Project-URL: Homepage, https://github.com/Ax1zz/certlens
Project-URL: Repository, https://github.com/Ax1zz/certlens
Project-URL: Issues, https://github.com/Ax1zz/certlens/issues
Keywords: security,tls,ssl,certificate-authority,root-certificate,trust-store,ccadb,mitm,audit,pki
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# certlens

**Your machine trusts ~150 certificate authorities. Do you know who they are?**

certlens reads a trust store, joins it against the Common CA Database, and
tells you who operates every root you trust, which government they answer to,
and which roots nobody's root program vouches for.

[![PyPI](https://img.shields.io/pypi/v/certlens.svg)](https://pypi.org/project/certlens/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/Ax1zz/certlens/blob/main/LICENSE)
[![Python](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/)
[![Dependencies](https://img.shields.io/badge/runtime%20dependencies-none-brightgreen.svg)](https://github.com/Ax1zz/certlens/blob/main/pyproject.toml)
[![Tests](https://img.shields.io/badge/tests-139%20passing-brightgreen.svg)](https://github.com/Ax1zz/certlens/tree/main/tests)
[![Read only](https://img.shields.io/badge/trust%20store-read--only-informational.svg)](https://github.com/Ax1zz/certlens/blob/main/SPEC.md)

[English] · [Русский](https://github.com/Ax1zz/certlens/blob/main/README.ru.md)

---

![certlens scanning a trust store](https://raw.githubusercontent.com/Ax1zz/certlens/main/docs/terminal.png)

*Real output. That scan found two TLS-interception proxies and an unidentified
root on the machine it ran on.*

---

## The problem

Any one of the ~150 root CAs your machine trusts can issue a certificate for
**any domain**, and your browser will accept it silently. Most people have
never looked at the list. The tooling to *enumerate* a trust store exists. The
tooling to *judge* one did not.

This is not a hypothetical concern, and it is not a niche one:

> "Windows trusts 322 root certificates issued by 122 different organizations.
> I think this is a good point I would never trust 122 people in my life with
> my bank-account details. But if I trust my browser it seems that is exactly
> what I'm doing. **Isn't there a better way?**"
> — [Hacker News](https://news.ycombinator.com/item?id=24828702), on a 255-point thread

> "Is there any tool out there that will monitor my system's use of root CAs?
> **So far I have not found anything** … there are root CAs I do not think I
> need to trust; Hong Kong Post Office comes to mind as one I would rather not
> trust."
> — [security.stackexchange.com](https://security.stackexchange.com/questions/273270/is-there-a-tool-for-auditing-my-root-certificates), Nov 2023

> "Is there a way to check if any non-standard root CAs have been added to my
> browser, **without going through them one by one and comparing them to a
> fresh install?** … It's too easy for arbitrary programs to add root CAs."
> — [Hacker News](https://news.ycombinator.com/item?id=9122996), after the Superfish scandal

> "There are now tons of Certification Authorities (CAs) that are trusted by
> default in major OS's, **many of which are unrecognizable without online
> lookup or reference.**"
> — [security.stackexchange.com](https://security.stackexchange.com/questions/71171/is-there-anything-preventing-the-nsa-from-becoming-a-root-ca), 177 votes, 25,884 views

And the stakes are documented history, not speculation:

| When | What |
|---|---|
| **2019** | Kazakh ISPs required a government root on every device. Mozilla and Google [blocked it](https://blog.mozilla.org/en/mozilla/mozilla-takes-action-to-protect-users-in-kazakhstan/): *"once installed, allowed the government to decrypt and read anything a user types or posts."* |
| **2020** | Kazakhstan tried again. Mozilla, Apple, Google and Microsoft [all blocked it](https://blog.mozilla.org/netpolicy/2020/12/18/kazakhstan-root-2020/). |
| **2022** | Russia's Ministry of Digital Development issued its own root, valid until 2032. EFF: *"[paves the way for a decade of digital surveillance](https://www.eff.org/deeplinks/2022/03/you-should-not-trust-russias-new-trusted-root-ca)."* |
| **2023** | EU eIDAS Article 45 would have forced browsers to trust state-designated CAs. [504 scientists from 39 countries objected](https://epicenter.works/fileadmin/user_upload/eIDAS_Open_Letter-2023-11-01-Academics_NGOs.pdf). |
| **2024** | Chrome [distrusted Entrust](https://chrome.security/2024/06/27/sustaining-digital-certificate-security.html) after *"a pattern of compliance failures."* |

certlens exists so you can answer the question for your own machine, in two
seconds, without reading 150 certificates by hand.

---

## Install

```bash
pip install certlens
```

No runtime dependencies. A tool that tells you what to trust should not ask you
to trust a dependency tree first.

## Quick start

```bash
certlens                      # audit the system trust store
certlens scan node            # audit Node.js's compiled-in roots
certlens stores               # list every trust store on this machine
certlens explain "Hongkong Post"
```

### Answer the "should I remove this?" question

![certlens explain](https://raw.githubusercontent.com/Ax1zz/certlens/main/docs/explain.png)

### Use it as a CI gate

Fail a build when an unexpected root is baked into an image:

```bash
certlens scan --fail-on high
```

Exit codes: `0` clean · `1` findings at or above the threshold · `2` error.

```yaml
# .github/workflows/trust.yml
- run: pip install certlens
- run: certlens scan --fail-on high
```

### Other output formats

```bash
certlens scan -f json | jq '.findings[] | select(.severity=="high")'
certlens scan -f html -o report.html
certlens refresh              # pull the newest CCADB data
```

---

## What it detects

| Finding | Severity | Meaning |
|---|---|---|
| `REVOKED_ROOT_TRUSTED` | critical | CCADB says revoked; it is still in your store |
| `UNRECOGNISED_ROOT` | high | In no root program, matching no known product |
| `LOCAL_INTERCEPTION_ROOT` | high/medium | A known proxy, antivirus or dev tool root — named |
| `NO_ROOT_PROGRAM` | high | Known CA, included by no vendor |
| `SHORT_LIVED_ROOT` | high | Unknown root valid under a year — a proxy signature |
| `EXPIRED_ROOT` | medium | Expired but still trusted |
| `STALE_AUDIT` | low | Audit period ended over 460 days ago |
| `STATE_OPERATED_CA` | low | Operator is a government or state-owned body |
| `CA_INCIDENT_HISTORY` | low | Operator has a documented distrust event |
| `WIDE_DELEGATION` | info | 5+ external organisations can issue under this root |
| `JURISDICTION_CONCENTRATION` | info | One country holds over 30% of your roots |

certlens recognises roots from Burp Suite, Fiddler, Charles, mitmproxy, mkcert,
HTTP Toolkit, Proxyman, Zscaler, Netskope, Palo Alto, Fortinet, Forcepoint,
Blue Coat, Cisco Umbrella, Sophos, McAfee, Kaspersky, Avast, AVG, Bitdefender
and ESET — so a legitimate corporate proxy shows up as *named*, not as an
unexplained mystery.

---

## How it compares

| | certlens | [trust_stores_observatory](https://github.com/nabla-c0d3/trust_stores_observatory) | [paranoia](https://github.com/jetstack/paranoia) | [cert-manage](https://github.com/adamdecaf/cert-manage) | `openssl`/`certmgr` |
|---|---|---|---|---|---|
| Lists your roots | yes | yes | container images only | yes | yes |
| Names the **operator** | yes | no | no | no | no |
| Shows **jurisdiction** | yes | no | no | no | no |
| Flags **state-operated** CAs | yes | no | no | no | no |
| Detects **injected/proxy** roots | yes | no | no | no | no |
| Names the proxy **product** | yes | no | no | no | no |
| Vendor-program membership | yes | partial | no | no | no |
| Audit staleness | yes | no | no | no | no |
| CI exit codes | yes | no | yes | no | no |
| HTML report | yes | no | no | no | no |
| Runtime dependencies | **none** | several | Go binary | Go binary | n/a |
| Modifies your store | **never** | no | no | yes | yes |

The closest thing ever built for the specific "which of these are governments?"
question was [certaintls](https://github.com/certaintls/certaintls) — 8 stars,
last touched in 2021, and it keyed on country freedom scores rather than
operator identity.

---

## How it works

1. Enumerate certificates from the chosen store, read-only.
2. SHA-256 fingerprint each one.
3. Join against [CCADB](https://www.ccadb.org/), the database Mozilla, Apple,
   Microsoft, Google and Cisco use to run their root programs. certlens ships a
   snapshot (940 roots), so it works offline and in air-gapped CI.
4. Apply the rule set and rank by severity.

Decoding uses the standard library's `ssl` module — the same OpenSSL your
Python already relies on. certlens hand-rolls no cryptography.

**certlens never modifies a trust store.** There is no code path that writes to
one. Removing roots breaks machines in confusing ways; certlens gives you the
information and gets out of the way.

---

## A note on language

"State-operated" here is a statement about corporate structure — the operator is
a government body or state-owned enterprise — not an accusation of wrongdoing.
Plenty of state-run CAs are well-administered. The point is that you should
know, and right now most people cannot find out.

---

## Roadmap

- [ ] Windows CTL trust store support
- [ ] Firefox NSS `cert9.db` reader
- [ ] `--diff` against a previously saved scan, for fleet drift detection
- [ ] SARIF output for code-scanning dashboards
- [ ] Optional check of which roots your machine has actually *used*
- [ ] Community-maintained interception-product signature list

## Contributing

See [CONTRIBUTING.md](https://github.com/Ax1zz/certlens/blob/main/CONTRIBUTING.md). The most valuable contributions are new
interception-product signatures and corrections to the state-operator mapping —
both live in [`certlens/knowledge.py`](certlens/knowledge.py) and both are
plain data.

```bash
git clone https://github.com/Ax1zz/certlens
cd certlens
python3 -m unittest discover -s tests -t .
```

## Data and licence

Certificate authority data comes from the [Common CA Database](https://www.ccadb.org/),
published by the CCADB and used here under its terms of use. certlens is not
affiliated with CCADB, Mozilla, or any certificate authority.

certlens is released under the [MIT licence](https://github.com/Ax1zz/certlens/blob/main/LICENSE).
