Fast, modular TLS/SSL security scanner and compliance engine built in Rust
CipherRun is a comprehensive TLS/SSL security scanner written in Rust. It combines protocol and cipher analysis, vulnerability testing, compliance checks, and certificate transparency monitoring in a single high-performance CLI and API-ready engine.
| Feature | Description |
|---|---|
| Protocol Coverage | SSLv2 to TLS 1.3 with full handshake analysis |
| Vulnerability Tests | 18+ major TLS CVEs (Heartbleed, ROBOT, POODLE, LOGJAM, etc.) |
| Compliance Engine | PCI-DSS, NIST, HIPAA, SOC 2, Mozilla, GDPR |
| Fingerprinting | JA3, JA3S, JARM with signature databases |
| Certificate Analysis | Chain validation, revocation, EV detection |
| Monitoring | 24/7 certificate monitoring with alerts |
| CT Logs | Real-time CT log streaming + Bloom deduplication |
| Database Support | PostgreSQL/SQLite analytics and history |
Compliance reports are TLS posture checks mapped to selected technical controls. Passing them does not establish certification or full regulatory compliance.
Requires Rust 1.88 or newer.
git clone https://github.com/seifreed/cipherrun.git
cd cipherrun
cargo build --release
./target/release/cipherrun --helpExport the versioned scan-result contract with cipherrun schema --output scan-results.schema.json; the repository copy is maintained at
docs/scan-results.schema.json.
The workspace also publishes cipherrun-core, a dependency-light crate with
the stable finding status, detection method, vulnerability identifiers, and
structured evidence contracts. It can be used without compiling the CLI, API,
database, or monitoring modules.
It also publishes cipherrun-protocol, which exposes the dependency-light
TLS/SSL protocol version and negotiation-result contracts independently of the
scanner implementation.
The cipherrun-policy crate provides the versioned policy-definition contracts
without pulling in the evaluator, database, or API server.
The cipherrun-data crate provides dependency-light rule-pack metadata
contracts without pulling in the compliance loader or scanner runtime.
The cipherrun-probes crate provides dependency-light probe status contracts
without pulling in the scanner networking runtime.
The cipherrun-cli crate provides stable process exit-code contracts for
integrations without pulling in the command router.
The cipherrun-server crate provides stable permission and job-backend
contracts without pulling in Axum, SQLx, or the scan executor.
The cipherrun-worker crate is a standalone worker binary that reuses the
main package's durable queue and scan executor.
Certificate Transparency streaming is enabled by default and can be removed
from a reduced build with --no-default-features; monitoring depends on
the ct feature because CT discovery feeds the monitor sink.
The HTTP API stack is enabled by the api feature (included by default). A
reduced CLI/library build can disable it with --no-default-features; API
server and OpenAPI commands then return an explicit configuration error and
the Axum/Tower/utoipa dependencies are omitted.
The standalone PQC configuration scanners and roadmap are enabled by the
pqc feature; readiness scoring remains part of the core scan-result contract.
The reduced feature matrix is checked in CI with --no-default-features,
monitoring, ct,pqc, both database backends, and --all-features builds.
Database backends are explicit features: db-sqlite and db-postgres are
enabled by default, and a disabled backend is rejected before opening a pool.
TLS provider selection is explicit as well. The default build enables
rustls (the ring provider) and openssl-legacy (the reproducible vendored
OpenSSL build). Reduced builds may omit either feature: rustls then uses its
default aws-lc-rs provider, while OpenSSL resolves against the system library.
cargo install cipherrunPushing a tag matching the package version, such as v0.4.0, runs the release workflow. It publishes cipherrun-core and then cipherrun to crates.io, and attaches platform packages for Linux, Windows, and macOS on x64 and ARM64, together with SHA-256 checksums. The workflow requires the repository Actions secret CARGO_REGISTRY_TOKEN.
The same release job generates cipherrun.rb and cipherrun.json assets from
those checksums for Homebrew and Scoop consumption. It also publishes the versioned production
image to GHCR and signs it keylessly with Sigstore. The local signing helper is
scripts/sign-container.sh.
The OpenAPI contract can be exported and used to regenerate the Python client:
cargo run --bin cipherrun-openapi > /tmp/cipherrun-openapi.json
scripts/generate-python-sdk.sh sdk/pythonThe default image is the production build: a distroless, non-root runtime containing only CipherRun and the CA bundle.
docker build -t cipherrun:0.4.0 .
docker run --rm cipherrun:0.4.0 example.comTo run the API, generate credentials first. The production Compose binds the API to localhost, mounts the configuration read-only, drops every capability, and uses a read-only root filesystem.
cipherrun --api-config-example ./api.toml
export CIPHERRUN_API_CONFIG="$PWD/api.toml"
docker compose -f compose.production.yml up --buildThe bootstrap command writes only a SHA-256 credential hash to api.toml and
places the one-time plaintext token in api.token; both files are created with
owner-only permissions and existing files are never overwritten. Move the token
to your secret manager and remove the local token file after enrollment.
Administrators can rotate or revoke credentials without restarting the API:
GET /api/v1/credentials, POST /api/v1/credentials,
POST /api/v1/credentials/{key_id}/rotate, and
POST /api/v1/credentials/{key_id}/revoke. Create and rotate responses contain
the new plaintext secret once; list and revoke responses contain metadata only.
Changes are synchronously persisted to the owner-only API TOML file, and the
last active administrator credential cannot be revoked.
CT streaming can feed the existing monitoring scheduler, scanner, and alert channels. Configure an explicit suffix allowlist in the monitor TOML:
[monitor]
ct_discovery_suffixes = ["example.com"]Then run cipherrun --ct-logs --ct-monitor-config monitor.toml. CT names are
deduplicated, normalized, and rejected unless they match an allowlisted suffix;
an empty allowlist performs no discovery.
Set job_storage_dir in api.toml for durable standalone job state. Queued,
running, completed, failed, and cancelled jobs survive restarts; interrupted
running jobs are safely returned to the queue. Omitting it selects the
development-only in-memory backend.
Set job_backend = "database" when the API is started with a configured
SQLite or PostgreSQL pool to use the transactional SQL job table instead of
file storage. Database jobs use conditional claims and recover expired running
leases on startup.
For distributed execution, set local_executor = false in the API config and
run one or more workers against the same SQL database:
cipherrun --worker --api-config api.toml --db-config database.tomlWorkers reuse the scanner, lease heartbeat, retry, dead-letter, webhook, and
CIDR policy code from the API executor; local_executor = false is rejected
unless job_backend = "database" is selected.
Running jobs renew their database lease while scanning. Transient scan failures
are retried up to three attempts; exhausted jobs remain queryable as failed
dead-letter records instead of being silently discarded.
job_retention_seconds controls terminal job TTL (seven days by default);
queued and running work is never removed by retention cleanup.
Browser WebSocket clients obtain a 60-second, one-use URL from
POST /api/v1/scan/{id}/stream-ticket using the X-API-Key or
Authorization: Bearer header. Raw API credentials in query parameters are
rejected.
To enable scan-completion webhooks, point webhook_signing_secret_file at an
owner-only file containing at least 32 random bytes. Deliveries include
X-CipherRun-Event, X-CipherRun-Delivery, X-CipherRun-Timestamp, and an
X-CipherRun-Signature: v1=<hex HMAC-SHA256> over <timestamp>.<body>; transient
failures are retried up to three times.
Authenticated operators can scrape /api/v1/metrics in Prometheus text format.
Every API response also carries an X-Request-ID value for correlating logs
and client reports. Requests are recorded in a bounded audit ring and emitted
through the structured audit tracing target; query strings and bodies are
intentionally excluded.
Credentials assigned to the same tenant_id share the configured request quota;
unscoped credentials remain isolated per key.
Set worker_allowed_cidrs in the API config to constrain worker DNS results to
administrator-owned network scopes. The client cannot widen this list; every
resolved private address must match an allowlisted CIDR.
Set trusted_proxy_cidrs before deploying behind a reverse proxy. X-Forwarded-For
is ignored unless the immediate TCP peer belongs to one of these CIDRs.
Historical scans, certificate inventory, and /api/v1/stats are scoped to the
authenticated principal and tenant for non-admin credentials. Administrator
credentials retain global visibility; process-wide counters are never exposed to
non-admin callers.
Build with --features otel to export tracing spans through the standard OTLP
HTTP exporter. The exporter follows OTEL_EXPORTER_OTLP_* environment variables;
without that feature, no telemetry backend is contacted.
Native HTTPS is available by setting tls_cert_file and tls_key_file to a
certificate chain and private-key PEM file. The two paths must be configured
together; otherwise the API remains HTTP for local development. TLS handshakes
are completed before Axum receives a connection.
Set tls_client_ca_file to a PEM CA bundle to require client certificates for
every HTTPS connection (mTLS). Keep the CA file owner-readable and distribute
client certificates separately from API credentials.
Dockerfile.lab and compose.lab.yml are an explicit packet-capture laboratory with pinned sslscan/testssl.sh sources and digest-pinned SSLyze/TLS-Scanner services. It grants NET_ADMIN and NET_RAW; use it only on systems and targets you are authorized to test.
mkdir -p captures results
docker compose -f compose.lab.yml run --rm cipherrun-lab
make lab-validatemake lab-validate starts isolated weak and modern TLS fixtures, records CipherRun,
sslscan, SSLyze, testssl.sh, TLS-Scanner, and OpenSSL results, and fails when the expected TLS 1.2/1.3
negotiation boundary changes. See the public validation coverage matrix.
# Scan a host
cipherrun example.com
# Scan a URL
cipherrun https://example.com
# Run full vulnerability scan
cipherrun -U example.com# Protocol testing
cipherrun -p example.com
# Explicit QUIC/UDP and HTTP/3 probe
cipherrun --quic example.com:443
# Offer Encrypted ClientHello from the target's HTTPS/SVCB record
cipherrun --ech example.com:443
# Cipher enumeration
cipherrun -e example.com
# JSON output
cipherrun --json results.json example.com
# HTML report
cipherrun --html report.html example.com
# CI artifacts
cipherrun --sarif results.sarif --junit results.junit.xml example.com
# CI failure thresholds
cipherrun --fail-on high example.com
cipherrun --policy policy.yaml --fail-on-policy example.com
# Compare versioned scan results (exit 4 on drift)
cipherrun diff baseline.json current.json
cipherrun --baseline baseline.json example.com
# Generate reviewable hardening snippets from a scan result
cipherrun remediate results.json --format nginx
cipherrun remediate results.json --format envoy --output envoy-tls.yaml
# Explicitly authorized internal-network scans (local CLI only)
cipherrun --allow-private intranet.example.internal
cipherrun --allow-cidr 10.20.0.0/16 host.internal
# Scan intensity presets
cipherrun --profile safe example.com
cipherrun --profile standard example.com
cipherrun --profile aggressive example.com# SMTP with STARTTLS
cipherrun -t smtp mail.example.com:587
# IMAP with STARTTLS
cipherrun -t imap mail.example.com:143JSON output is versioned independently from the CLI. The canonical schema, compatibility policy, changelog, and fixtures are published in schemas/.
Bundled compliance mappings carry an independent rule-pack version, primary publication reference, review date, and runtime SHA-256 of the exact YAML.
Remote timing probes follow the published timing methodology, including sample counts, descriptive statistics, confidence intervals, thresholds, and the conditions that produce an inconclusive verdict.
remediate generates configuration snippets for nginx, Apache, HAProxy, Envoy,
or Caddy. It never changes a running service, and it deliberately leaves
inconclusive or potential findings visible for operator review. Existing output
files are protected unless --overwrite is supplied.
cargo fmt --all --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test
cargo audit
cargo deny check
cargo +nightly udeps
cargo tarpaulin --engine llvm --all-features --all-targets --no-fail-fast --out Xml
cargo bench
cargo fuzz list
cargo fuzz build parsed_input
cargo outdatedCriterion benchmarks live in benches/, and cargo-fuzz targets plus seed corpora live in fuzz/.
Terminal, JSON, CSV, HTML, XML, SARIF 2.1.0, JUnit XML
Exit codes are stable for automation: 0 success, 1 operational/partial-scan
failure, 2 confirmed finding at the --fail-on threshold, and 3 failed
policy or mapped compliance checks. 4 reports drift from diff or a baseline.
- Scanner Engine: Async Tokio-based probes
- Protocols: SSLv2 → TLS 1.3
- Vuln Suite: 18+ checks
- Fingerprinting: JA3/JA3S/JARM
- Compliance: 7 frameworks
- Database: SQL migrations + analytics
Layer boundaries are enforced by tests/architecture_guards.rs.
Contributions are welcome:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
If you find CipherRun useful, consider supporting its development:
This project is licensed under GPL-3.0-or-later - see the LICENSE file for details.
Attribution Required:
- Author: Marc Rivero | @seifreed
- Repository: github.com/seifreed/cipherrun
Made with dedication for the security community