{"id":51008392,"url":"https://github.com/voidd0/sslcheck","last_synced_at":"2026-06-20T23:31:00.023Z","repository":{"id":354571330,"uuid":"1223785005","full_name":"voidd0/sslcheck","owner":"voidd0","description":"sslcheck — inspect TLS certificates for any host:port. Severity-aware exit codes for CI/cron monitors. Zero deps.","archived":false,"fork":false,"pushed_at":"2026-06-03T09:34:22.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T11:16:59.362Z","etag":null,"topics":["cert-expiry","certificate","ci","cli","devops","monitoring","nodejs","ssl","ssl-checker","tls","tls-checker","voiddo"],"latest_commit_sha":null,"homepage":"https://tools.voiddo.com/sslcheck/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voidd0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://voiddo.com/contact/","https://scrb.voiddo.com/"]}},"created_at":"2026-04-28T16:47:04.000Z","updated_at":"2026-06-03T09:34:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/voidd0/sslcheck","commit_stats":null,"previous_names":["voidd0/sslcheck"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/voidd0/sslcheck","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fsslcheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fsslcheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fsslcheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fsslcheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voidd0","download_url":"https://codeload.github.com/voidd0/sslcheck/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fsslcheck/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34589204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cert-expiry","certificate","ci","cli","devops","monitoring","nodejs","ssl","ssl-checker","tls","tls-checker","voiddo"],"created_at":"2026-06-20T23:30:59.947Z","updated_at":"2026-06-20T23:31:00.017Z","avatar_url":"https://github.com/voidd0.png","language":"JavaScript","funding_links":["https://voiddo.com/contact/","https://scrb.voiddo.com/"],"categories":[],"sub_categories":[],"readme":"# sslcheck\n\n[![npm version](https://img.shields.io/npm/v/@v0idd0/sslcheck.svg?color=A0573A)](https://www.npmjs.com/package/@v0idd0/sslcheck)\n[![npm downloads](https://img.shields.io/npm/dw/@v0idd0/sslcheck.svg?color=1F1A14)](https://www.npmjs.com/package/@v0idd0/sslcheck)\n[![License: MIT](https://img.shields.io/badge/license-MIT-A0573A.svg)](LICENSE)\n[![Node ≥14](https://img.shields.io/badge/node-%E2%89%A514-1F1A14)](package.json)\n\nInspect TLS certificates for any host:port. Reports issuer, SANs, validity window, days-until-expiry, key strength, chain depth. Zero deps. Free forever from vøiddo.\n\n```\n$ sslcheck voiddo.com\nvoiddo.com:443  [ok]\n  cn       voiddo.com\n  sans     voiddo.com, www.voiddo.com\n  issuer   R12\n  valid    Mar 31 05:05:45 2026 GMT  →  Jun 29 05:05:44 2026 GMT\n  expires  62 days (lifetime 90 days)\n  key      RSA 2048 bits\n  conn     TLSv1.3  TLS_AES_256_GCM_SHA384 (TLSv1.3)  36ms\n  chain    3 cert(s)\n```\n\n## Why sslcheck\n\nYou set up a Let's Encrypt cert eight months ago. Your auto-renew cron is supposed to handle it. Sometimes it doesn't, and the first sign is a customer pinging you about a browser warning. `openssl s_client -connect host:443 -servername host` does the same job, but the output is a wall of base64 that requires three more pipes to decode. sslcheck is the same probe formatted for human triage and shaped for cron exit codes.\n\n## Install\n\n```bash\nnpm install -g @v0idd0/sslcheck\n```\n\n## Usage\n\n```bash\n# Single host (port defaults to 443)\nsslcheck voiddo.com\n\n# Multiple hosts\nsslcheck github.com npmjs.com cloudflare.com\n\n# Custom port\nsslcheck mta.example.com:587\n\n# Override SNI (useful for self-signed / shared infra)\nsslcheck self-signed.badssl.com --servername example.com\n\n# JSON for CI / scripts\nsslcheck voiddo.com --json | jq '.leaf.days_until_expiry'\n\n# Dump leaf cert as PEM\nsslcheck voiddo.com --json --pem | jq -r '.pem' \u003e leaf.pem\n\n# Custom timeout (ms, default 8000)\nsslcheck slow-host.example.com --timeout 15000\n```\n\n## What it reports\n\n| Field | Meaning |\n|---|---|\n| `severity` | `ok` / `warn` / `critical` (also drives exit code) |\n| `reasons` | Why severity isn't `ok` (e.g., `\"expires in 14 days\"`, `\"self-signed\"`) |\n| `leaf.common_name` | The CN on the leaf cert |\n| `leaf.sans` | All `subjectAltName` DNS entries |\n| `leaf.issuer_cn` | Who signed it |\n| `leaf.valid_from` / `valid_to` | Cert validity window |\n| `leaf.days_until_expiry` | Negative if expired |\n| `leaf.key_type` / `key_bits` | RSA 2048, ECDSA P-256, etc. |\n| `leaf.fingerprint_sha256` | For pinning / monitoring |\n| `protocol` / `cipher` | Negotiated TLS version + cipher suite |\n| `chain_length` | Number of certs in the served chain |\n| `authorized` | Did node's default trust store accept this chain? |\n\n## Severity rules\n\n- `critical` — expired, expires in ≤ 7 days, RSA key \u003c 2048 bits, or chain not authorized\n- `warn` — expires in ≤ 30 days, or self-signed\n- `ok` — none of the above\n\nExit code is `1` on any `critical`, `0` otherwise — wire it directly into monitors/CI.\n\n## Compared to alternatives\n\n| tool | exit code | JSON | per-cert key strength | offline | install |\n|---|---|---|---|---|---|\n| sslcheck | yes (severity-based) | yes | yes | needs network for handshake | one npm install |\n| `openssl s_client` | always 0 unless connection fails | no | manual | needs network | bundled |\n| `testssl.sh` | yes | yes (huge) | yes (deep) | needs network | bash + many deps |\n| SSL Labs (web) | n/a | yes (API) | yes | no | web only |\n| `openssl x509 -in cert.pem` | manual | no | manual | yes (file-only) | bundled |\n\nFor a comprehensive cipher-suite + protocol weakness audit, `testssl.sh` is the deeper tool. For \"is this cert about to expire?\" run by cron every morning, sslcheck is the smaller hammer.\n\n## FAQ\n\n**Why default 8s timeout?** Because some hosts negotiate TLS slowly through carrier-grade NAT / corporate proxies, and 8s is enough for typical pathological cases without making CI feel hung.\n\n**Does it check OCSP?** No. OCSP stapling is increasingly skipped by browsers in favour of CRLite-style models, and our default checks (expiry / chain / key strength) cover the operationally relevant failure modes.\n\n**SANs longer than the terminal width?** They wrap. Use `--json` for programmatic parsing.\n\n**What does `authorized: false` mean?** Node's default trust store rejected the chain. Could be self-signed, could be unknown CA, could be missing intermediate. Pair with `--servername` if you suspect SNI mismatch.\n\n## CI / cron usage\n\n```bash\n# Daily expiry watcher (cron)\nsslcheck \\\n  voiddo.com \\\n  tells.voiddo.com \\\n  scrb.voiddo.com \\\n  --json | \\\n  jq -e '[.[]|select(.leaf.days_until_expiry \u003c 14)]|length == 0' \\\n  || alert-ops \"TLS cert nearing expiry\"\n```\n\n## Programmatic API\n\n```javascript\nconst { inspect } = require('@v0idd0/sslcheck');\n\nconst r = await inspect('voiddo.com', { timeout: 5000 });\nif (r.severity === 'critical') {\n  console.error(`${r.target} — ${r.reasons.join('; ')}`);\n}\n```\n\n## More from the studio\n\nThis is one tool out of many — see [`from-the-studio.md`](from-the-studio.md) for the full lineup of vøiddo products (other CLI tools, browser extensions, the studio's flagship products and games).\n\n## From the same studio\n\n- **[@v0idd0/jsonyo](https://www.npmjs.com/package/@v0idd0/jsonyo)** — JSON swiss army knife, 18 commands, zero limits\n- **[@v0idd0/envguard](https://www.npmjs.com/package/@v0idd0/envguard)** — stop shipping `.env` drift to staging\n- **[@v0idd0/depcheck](https://www.npmjs.com/package/@v0idd0/depcheck)** — find unused dependencies in one command\n- **[@v0idd0/gitstats](https://www.npmjs.com/package/@v0idd0/gitstats)** — git repo analytics, one command\n- **[View all tools →](https://voiddo.com/tools/)**\n\n## License\n\nMIT.\n\n---\n\nBuilt by [vøiddo](https://voiddo.com/) — a small studio shipping AI-flavoured products, free dev tools, Chrome extensions and weird browser games.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidd0%2Fsslcheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoidd0%2Fsslcheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidd0%2Fsslcheck/lists"}