peep is a TLS diagnostic tool for support engineers, SREs, platform folks, and anyone who is tired of pretending hex dumps are a personality. It peeps into TLS handshakes & certificate chains, & tells you what's broken in plain English, instead of cryptographic cave paintings β because "PKIX path building failed" was not helpful.
$ peep self-signed.badssl.com
β Peeping at self-signed.badssl.com:443
β IP: 104.154.89.105
β Protocol: Direct TLS
β Direct TLS handshake completed successfully
β
β β SERVER DID NOT INCLUDE THE ISSUING CA IN ITS RESPONSE
β One job. You had ONE job. Bundle the certs correctly. ONE. JOB.
β
β Verdict: Appears to be Written in Crayon
β If this cert were a building, it would've been condemned.
β
β Findings: 3 issue(s) detected
β [WARN] Self-Signed Certificate
β [FAIL] No Issuing CA in Server Response
β [FAIL] Chain Verification Failed
β
β [PASS] TLS: TLSv1.2
β [PASS] Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
β CHAIN OF TRUST
β
β [WARN] Leaf *.badssl.com
β Expires: 725 days (Apr 20, 2028)
β Covers: *.badssl.com, badssl.com
β Key: RSA
β Serial: EC7256235A58C012
β SHA-256: 3F2A:DC71:E756:...
β Self-signed!
β
β [FAIL] No Issuing CA in server response
β The chain has exactly one link. That's not a chain. That's a pendant.
β
β [FAIL] Trust store verification failed
β x509: certificate signed by unknown authority
β Trust store says no. Browsers say no. I say no. Everybody says no.
Because openssl s_client was designed for cryptographers, not for the person at 2 AM trying to figure out why the load balancer is returning the wrong cert.
| The Problem | peep |
|---|---|
openssl s_client -connect host:443 -servername host < /dev/null 2>/dev/null | openssl x509 -noout -text |
peep host |
| "PKIX path building failed" | "Missing intermediate cert β the server needs to send it" |
| "unable to get local issuer certificate" | "Chain verification failed β here's exactly which cert is wrong and why" |
SMTP STARTTLS: add -starttls smtp and pray |
peep mail.company.com:587 |
| RDP certs: β openssl can't even | peep rdp-server:3389 just works |
| Manually checking OCSP, CRL, CT, ciphers separately | peep scan host checks everything in one shot |
| "It works in Chrome" (because Chrome does AIA chasing) | peep shows what curl, Go, Java, and Python actually see |
| Output designed for robots | Output designed for humans (with --json for the robots too) |
| No fix recommendations | peep --explain host tells you exactly what to do |
Zero dependencies. Zero telemetry. Single binary. Runs locally.
After installing, try these against badssl.com to see peep in action:
# Self-signed cert β watch peep roast it
peep self-signed.badssl.com
# Expired cert β see exactly when it died
peep expired.badssl.com
# Wrong hostname β SNI mismatch
peep wrong.host.badssl.com
# Missing intermediate β the "works in Chrome but breaks everywhere else" problem
peep incomplete-chain.badssl.com
# Get explanations and fix recommendations for every finding
peep incomplete-chain.badssl.com --explain
# Full deep scan β ciphers, OCSP, CRL, CT logs, TLS version probing
peep scan google.com
# SMTP with STARTTLS
peep smtp.gmail.com:587
# See graduated examples for any command (simple β advanced β JSON + jq)
peep --examples
peep scan --examplesbrew install thexsa/tap/peepcurl -sSfL https://raw.githubusercontent.com/thexsa/peep/main/install.sh | shDetects your OS and architecture, downloads the latest release, verifies the SHA-256 checksum, and asks where you'd like to install.
go install github.com/thexsa/peep/cmd/peep@latestRequires Go 1.23+.
Grab the latest binary for your platform from the Releases page:
| Platform | Binary |
|---|---|
| macOS (Apple Silicon) | peep-darwin-arm64 |
| macOS (Intel) | peep-darwin-amd64 |
| Linux (x86_64) | peep-linux-amd64 |
| Linux (ARM64) | peep-linux-arm64 |
| Linux (ppc64le) | peep-linux-ppc64le |
| AIX (ppc64) | peep-aix-ppc64 |
| Windows (x86_64) | peep-windows-amd64.exe |
# Download, make executable, add to PATH (example for macOS ARM)
curl -LO https://github.com/thexsa/peep/releases/latest/download/peep-darwin-arm64
chmod +x peep-darwin-arm64
sudo mv peep-darwin-arm64 /usr/local/bin/peepWindows: Download peep-windows-amd64.exe, rename to peep.exe, and place in a directory in your %PATH%.
Requires Go 1.23+. No CGO, no OpenSSL, no external dependencies.
git clone https://github.com/thexsa/peep.git
cd peep
make build # Build for your platform β ./peep
make build-all # Cross-compile all 7 platforms β dist/Just give peep a host and port. It figures out the rest.
| Port | Protocol | What peep does |
|---|---|---|
| 443 | HTTPS | Direct TLS handshake |
| 587/25 | SMTP | STARTTLS upgrade |
| 3389 | RDP | X.224 negotiation β TLS (where openssl fails!) |
| 636 | LDAPS | Direct TLS |
| 389 | LDAP | STARTTLS extended operation |
| 993/995 | IMAPS/POP3S | Direct TLS |
| 21 | FTP | AUTH TLS upgrade |
Override with -P/--proto when services run on non-standard ports:
peep -P smtp mailserver:2525See exactly who signed what, whether the chain is complete, and what role each cert plays β with serial numbers and SHA-256 fingerprints.
Don't just show the problem β explain it, recommend a fix, and link to the relevant built-in docs:
$ peep --explain example.com
β [FAIL] No Issuing CA in Server Response
β The server did not include the issuing CA certificate ...
β
β Why this matters:
β During the TLS handshake, the server is expected to send the
β complete certificate chain ...
β
β Recommended fix:
β Add the issuing CA (intermediate) certificate to the server's
β cert chain. Concatenate them: cat leaf.crt intermediate.crt > fullchain.crt ...
β
β π Learn more: peep docs chainLearn TLS concepts without leaving the terminal:
peep docs # Table of contents
peep docs tls # What is TLS?
peep docs certs # Leaf vs Intermediate vs Root
peep docs chain # How chain of trust works
peep docs ciphers # Cipher suites explained
peep docs crl # Certificate Revocation Lists
peep docs ocsp # OCSP β stapled vs live, Must-Staple
peep docs aia # AIA chasing & "works in Chrome" gotcha
peep docs tls-handshake # TLS 1.2 vs 1.3 handshake flows
peep docs starttls # What STARTTLS is
peep docs rdp # Why RDP certs are special
peep docs troubleshooting # Common issues checklistPipe to jq, feed into monitoring, or parse in CI/CD:
peep --json example.com | jq '.overall_status'
peep --json --explain example.com | jq '.warnings[].fix'Not sure how to use a command? Add --examples to any command for graduated usage examples β from simple to advanced β always ending with JSON + jq extraction queries:
peep --examples # Examples for the root command
peep scan --examples # Examples for deep scans
peep docs --examples # Examples for the docs browser
peep update --examples # Examples for self-updateThe deep scan checks CRL revocation by fetching the Certificate Revocation List and verifying the certificate serial is not present.
LDAP distribution points (common with Microsoft AD CS) are automatically detected and skipped β peep will try HTTP endpoints instead and provide the ldapsearch command for manual verification from a domain-joined machine.
TLS endpoint warnings: If the CRL endpoint has a certificate error (e.g., hostname mismatch), peep still fetches and verifies the CRL data (it's signed by the CA, so transport-layer TLS isn't required for integrity), but warns you.
Every finding comes with rotating sarcastic remarks. Because debugging TLS should at least be entertaining.
peep checks for updates automatically (once every 24 hours) and notifies you after scan output:
π‘ Update available: v1.3.0 β v1.4.0 (run `peep update` to upgrade)
Update with a single command β peep auto-detects whether you installed via Homebrew or GitHub binary:
peep update # Update to latest
peep update --check # Just check, don't installDisable automatic checks: set PEEP_NO_UPDATE_CHECK=1 in your environment.
# Quick check (defaults to port 443)
peep example.com
# Specific port (always host:port format)
peep example.com:8443
# Detailed cert info cards (subject, issuer, key info, SANs, etc.)
peep -d example.com
# Base64 PEM encoded certs
peep -v example.com
# Raw x509 text output (like openssl x509 -text)
peep -r example.com
# Explain every issue with fixes and doc references
peep -e example.com
# JSON output (for scripting / CI/CD)
peep -j example.com
peep -j -e -v example.com
# Save all cert PEMs to files
peep --save example.com
# Save a specific cert by chain index (0=leaf, 1=intermediate, etc.)
peep --save=0 example.com
# SMTP (auto-detects STARTTLS)
peep mail.example.com:587
# RDP (handles X.224 negotiation)
peep rdp-server.example.com:3389
# Force protocol on non-standard port
peep -P smtp mailrelay.internal:2525
# Plain text output (no color, no emoji β easy to copy/paste)
peep -p example.com
# Deep scan (cipher enumeration, OCSP staple + live, CRL, CT logs, SSL/TLS version probing)
peep scan example.com
# Deep scan with explanations and remediation advice
peep scan --explain example.com
# Skip trust store verification (for self-signed certs)
peep -i internal-server.local:443
# Built-in docs
peep docs certs
# Check for updates
peep update --check
# Update to latest version
peep update
# Contextual examples for any command
peep --examples
peep scan --examples
peep docs --examplesEvery flag has a standard name and a fun themed alias. Use whichever speaks to you.
| Short | Flag | Themed Alias | Description |
|---|---|---|---|
-d |
--details |
--gaze |
Show detailed cert info cards |
-e |
--explain |
--whytho |
Explain each issue with fix recommendations and doc references |
-h |
--help |
Show help | |
-i |
--insecure |
--blindfold |
Skip system trust store verification |
-j |
--json |
JSON output for scripting (respects -d, -v, -e) | |
-p |
--plain-text |
--shades |
No color, no emoji, no Unicode β easy to copy/paste |
-P |
--proto |
--lens |
Force protocol: tls, smtp, rdp, ldap, ftp |
-r |
--raw |
Raw x509 text output for each cert (like openssl x509 -text) |
|
-s |
--save |
--polaroid |
Save cert PEM(s) to files. No value = all, or specify index |
-t |
--timeout |
--blink |
Connection timeout in seconds (default: 5) |
-v |
--verbose |
--stare |
Show base64 PEM encoded certs |
--examples |
--show-me |
Show contextual usage examples with jq queries | |
--internal-ca |
Adjust grading for internal/private CA certs (skips SCT and 398-day checks) | ||
--ca-bundle |
Path to CA certificate bundle (.pem, .crt, .cer, .der) β replaces system trust store |
| Command | Description |
|---|---|
peep scan <host> |
Deep scan with cipher enumeration, OCSP, CRL, CT logs |
peep docs [topic] |
Built-in TLS reference |
peep update |
Update peep to the latest version (alias: peep upgrade) |
peep update --check |
Check for updates without installing (alias: --sniff) |
peep update --force |
Force update even if already on latest version |
peep version |
Show version, install method, and platform |
peep completion --install |
Install shell tab-completion (zsh, bash, fish, PowerShell) |
Flags work in any order and combine freely:
peep -j -e -v example.com # Full JSON with explanations and PEM certs
peep -d -j example.com # JSON with detailed cert info
peep --whytho example.com # CLI with issue explanations (themed alias)
peep --shades --whytho example.com # Copy/paste friendly with explanations
peep --polaroid example.com # Save all cert PEMs (themed alias)
peep --ogle example.com # Raw x509 output (themed alias)When scanning certificates signed by internal or private CAs (like Microsoft AD CS), peep automatically detects private CA characteristics using a confidence scoring system. In standard mode, it shows a CA Origin Assessment block with evidence when a non-public CA is suspected.
Explicitly tell peep the certificate is from an internal CA. This adjusts grading:
- SCT warnings are suppressed (internal CAs don't participate in Certificate Transparency)
- 398-day validity warnings are skipped (internal CAs commonly issue longer-lived certs)
- The CA origin assessment block is hidden
# Scan an internal server β skip public-CA-only checks
peep scan intranet.corp.local --internal-ca
# Combine with --insecure if the root CA isn't in your system store
peep scan intranet.corp.local --internal-ca --insecureReplace the system trust store with a custom CA certificate bundle. Works like curl --cacert β the specified file becomes the only trusted root(s).
Supports .pem, .crt, .cer (PEM-encoded) and .der (DER-encoded) files.
# Verify against your organization's root CA
peep scan mail.corp.local --ca-bundle /path/to/corp-root-ca.pem
# Combine with --internal-ca for proper grading
peep scan mail.corp.local --ca-bundle /path/to/corp-root-ca.crt --internal-capeep does not collect telemetry, analytics, or usage data.
The only outbound network requests peep makes are:
- TLS connections to the host you're scanning (that's the whole point)
- OCSP/CRL checks to the CA's responder (in
scanmode only, to verify revocation status) - Update checks to the GitHub Releases API (once every 24 hours, disabled with
PEEP_NO_UPDATE_CHECK=1)
No hostnames, certificates, scan results, or any other data is sent anywhere. Ever. peep is a local tool that runs on your machine and talks only to the hosts you point it at.
peep supports tab-completion for bash, zsh, fish, and PowerShell. This is optional β peep works fine without it.
Autocompletion lets you tab-complete commands and flags:
peep do<TAB> β peep docs
peep --ex<TAB> β peep --explain
One command β peep detects your shell and sets everything up:
peep completion --installThis will:
- Detect your current shell (zsh, bash, fish, or PowerShell)
- Write the completion script to
~/.peep/completions/ - Append the necessary source line to your shell's rc file (
.zshrc,.bashrc, etc.) - Never overwrite β only appends if not already present
- Running it again is safe (idempotent)
You can also specify the shell explicitly:
peep completion zsh --install
peep completion bash --install
peep completion fish --install
peep completion powershell --installWindows / PowerShell: peep completion --install appends to your $PROFILE. If you get an execution policy error, run:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUserIf you prefer to manage it yourself, generate the script to stdout:
peep completion zsh # print to stdout
peep completion bash # print to stdout
peep completion fish # print to stdout
peep completion powershell # print to stdoutNote: Autocompletion requires
peepto be in your$PATH(not just./peep). See the Installation section.
| Task | openssl | peep |
|---|---|---|
| Check a cert | openssl s_client -connect host:443 -servername host < /dev/null 2>/dev/null | openssl x509 -noout -dates |
peep host |
| Check SMTP cert | openssl s_client -connect host:587 -starttls smtp |
peep host:587 |
| Check RDP cert | β Can't | peep host:3389 |
| See the chain | openssl s_client -connect host:443 -showcerts |
peep host |
| Understand what's wrong | Read the hex and figure it out | peep tells you in English |
| Get fix recommendations | β Nope | peep --explain host |
| JSON for CI/CD | Roll your own parser | peep --json host |
- 100% Go β no CGO, no OpenSSL, no external runtime dependencies
- Single binary β download and run, nothing to install
- Cross-platform β macOS (ARM + Intel), Linux (amd64, arm64, ppc64le), AIX (ppc64), Windows (amd64)
- CLI framework β spf13/cobra (Apache 2.0)
- Terminal styling β charmbracelet/lipgloss (MIT)
- Terminal width β golang.org/x/term (BSD-3-Clause)
Contributions are welcome! See CONTRIBUTING.md for development setup, project structure, and PR guidelines.
Please read our Code of Conduct before contributing.
Apache 2.0 β see LICENSE for the full text.
Built with Go β no OpenSSL required.