Security Commands¶
The security group provides SSL/TLS certificate inspection, HTTP security
header auditing, email security record validation (SPF/DKIM/DMARC), subdomain
discovery, and continuous certificate monitoring.
nadzoring security --help
security check-ssl¶
Inspect the SSL/TLS certificate of one or more domains. Checks expiry date, issuer, subject, Subject Alternative Names (SAN), public key strength, domain match, and which TLS protocol versions the server accepts (TLSv1.0 through TLSv1.3).
By default a compact summary table is displayed. Use --full to include
the complete SAN list, protocol support details, chain length, and raw serial
number.
nadzoring security check-ssl [OPTIONS] DOMAIN [DOMAIN ...]
Options¶
Option |
Default |
Description |
|---|---|---|
|
|
Days before expiry at which to flag the certificate as |
|
off |
Disable certificate chain verification (useful for self-signed or internal CA certificates) |
|
off |
Show all fields — SAN list, protocol support, chain length, serial number — instead of the compact summary |
Status values¶
Status |
Meaning |
|---|---|
|
Certificate is valid and not near expiry |
|
Fewer than |
|
Certificate has already passed its expiry date |
|
Could not connect to the host or parse the certificate |
Examples¶
# Compact summary (default)
nadzoring security check-ssl example.com
# 30-day warning window, multiple domains
nadzoring security check-ssl --days-before 30 google.com github.com cloudflare.com
# Skip chain verification — useful for self-signed certs
nadzoring security check-ssl --no-verify internal.corp.example.com
# Full details: SAN, protocol support, chain, serial number
nadzoring security check-ssl --full ya.ru
# Save full JSON report
nadzoring security check-ssl --full -o json --save ssl_report.json example.com github.com
Python API¶
from nadzoring.security.check_website_ssl_cert import (
check_ssl_certificate,
check_ssl_expiry,
check_ssl_expiry_with_fallback,
)
# Verified check (full certificate chain validation)
result = check_ssl_certificate("example.com", days_before=14)
print(result["status"]) # 'valid' | 'warning' | 'expired' | 'error'
print(result["remaining_days"]) # e.g. 142
print(result["expiry_date"]) # '2025-10-15T12:00:00+00:00'
print(result["verification"]) # 'verified' | 'unverified' | 'failed'
# Subject and issuer
print(result["subject"]["CN"]) # 'example.com'
print(result["issuer"]["CN"]) # 'DigiCert TLS RSA SHA256 2020 CA1'
print(result["issuer"]["O"]) # 'DigiCert Inc'
# Subject Alternative Names
for san in result.get("san", []):
print(san) # 'DNS:example.com', 'DNS:www.example.com', ...
# Domain match
print(result["domain_match"]) # True
print(result["matched_names"]) # ['DNS:example.com']
# Public key
key = result["public_key"]
print(key["algorithm"]) # 'RSA' | 'EC' | 'Ed25519' | ...
print(key.get("key_size")) # 2048 (RSA / DSA only)
print(key.get("curve")) # 'secp256r1' (EC only)
print(key["strength"]) # 'weak' | 'good' | 'strong'
# TLS protocol support (TLSv1.0 – TLSv1.3)
protos = result["protocols"]
print(protos["supported"]) # ['TLSv1.2', 'TLSv1.3']
print(protos["has_outdated"]) # False — True if TLSv1.0 or TLSv1.1 supported
# Certificate chain (only when verify=True)
print(result.get("chain_length")) # 3
print(result.get("chain_valid")) # True
# Expiry-only check (lighter)
result = check_ssl_expiry("example.com")
# Automatic fallback to unverified if chain check fails
result = check_ssl_expiry_with_fallback("self-signed.badssl.com")
print(result["verification"]) # 'unverified' when fallback was used
security check-headers¶
Analyse the HTTP security headers returned by one or more URLs. Reports
which recommended headers are present or missing, identifies deprecated
headers (e.g. X-XSS-Protection), lists information-leaking headers
(e.g. Server, X-Powered-By), and produces a 0–100 coverage score.
nadzoring security check-headers [OPTIONS] URL [URL ...]
Options¶
Option |
Default |
Description |
|---|---|---|
|
|
HTTP request timeout in seconds |
|
off |
Disable SSL certificate verification for the request |
Checked security headers¶
Header |
Purpose |
|---|---|
|
Enforce HTTPS connections (HSTS) |
|
Mitigate XSS and injection attacks |
|
Prevent MIME-type sniffing |
|
Prevent clickjacking |
|
Legacy XSS filter (deprecated — flagged if present) |
|
Control referrer information leakage |
|
Restrict browser feature access |
|
Isolate cross-origin resources (COEP) |
|
Isolate browsing context groups (COOP) |
|
Control cross-origin resource sharing (CORP) |
|
Prevent caching of sensitive responses |
Examples¶
# Single URL
nadzoring security check-headers https://example.com
# Batch audit — multiple services at once
nadzoring security check-headers \
https://api.example.com \
https://admin.example.com \
https://static.example.com
# Internal endpoint — skip SSL verification
nadzoring security check-headers --no-verify https://internal.corp.example.com
# Slow server — increase timeout
nadzoring security check-headers --timeout 20 https://slow-api.example.com
# Export JSON for CI / dashboard
nadzoring security check-headers -o json --save headers_audit.json https://example.com
Python API¶
from nadzoring.security.http_headers import check_http_security_headers
result = check_http_security_headers(
"https://example.com",
timeout=10.0,
verify_ssl=True,
)
print(result["url"]) # final URL after any redirects
print(result["status_code"]) # HTTP status code (e.g. 200)
print(result["score"]) # 0–100 coverage score
# Headers that are correctly set
for header, value in result["present"].items():
print(f" ✓ {header}: {value}")
# Recommended headers that are absent
for header in result["missing"]:
print(f" ✗ {header}")
# Deprecated headers found in the response
for header in result["deprecated"]:
print(f" ⚠ deprecated: {header}")
# Headers that leak server or technology information
for header, value in result["leaking"].items():
print(f" ⚠ leaking: {header} = {value}")
if result["error"]:
print("Request failed:", result["error"])
security check-email¶
Validate the email security configuration of one or more domains. Checks:
SPF (Sender Policy Framework) — mechanism syntax,
+allmisuse, multiple SPF records, DNS lookup count.DKIM (DomainKeys Identified Mail) — probes 13 common selector names.
DMARC (Domain-based Message Authentication, Reporting and Conformance) — parses
p,sp,pct,rua,ruftags and flags weak policies.
Note
Requires one of the following to be available:
dnspythonPython package (pip install dnspython) — preferred; handles multi-chunk TXT records reliably.digsystem utility.nslookupsystem utility (fallback).
nadzoring security check-email [OPTIONS] DOMAIN [DOMAIN ...]
Examples¶
# Single domain
nadzoring security check-email gmail.com
# Multiple domains
nadzoring security check-email google.com github.com cloudflare.com
# All owned domains at once
nadzoring security check-email corp.example.com mail.example.com newsletter.example.com
# Full JSON report
nadzoring security check-email -o json --save email_security.json example.com
# Quiet mode — results only, no progress output
nadzoring security check-email --quiet example.com
Python API¶
from nadzoring.security.email_security import check_email_security
result = check_email_security("example.com")
print(result["domain"])
print(result["overall_score"]) # 0 = none found, 3 = SPF + DKIM + DMARC all present
# SPF
spf = result["spf"]
print(spf["found"]) # True
print(spf["record"]) # 'v=spf1 include:_spf.example.com ~all'
print(spf["mechanisms"]) # ['include:_spf.example.com']
print(spf["all_qualifier"]) # '~' (softfail — recommended minimum)
for issue in spf["issues"]:
print(" SPF issue:", issue)
# DKIM
dkim = result["dkim"]
print(dkim["found"])
print(dkim["selectors_checked"]) # list of 13 common selectors probed
for selector, record in dkim["records"].items():
print(f" DKIM selector '{selector}': {record[:60]}...")
for issue in dkim["issues"]:
print(" DKIM issue:", issue)
# DMARC
dmarc = result["dmarc"]
print(dmarc["found"])
print(dmarc["record"]) # 'v=DMARC1; p=reject; rua=mailto:...'
print(dmarc["policy"]) # 'none' | 'quarantine' | 'reject'
print(dmarc["subdomain_policy"]) # value of sp= tag, or None
print(dmarc["pct"]) # percentage the policy applies to
print(dmarc["rua"]) # aggregate report destinations
print(dmarc["ruf"]) # forensic report destinations
for issue in dmarc["issues"]:
print(" DMARC issue:", issue)
# All issues aggregated across SPF + DKIM + DMARC
for issue in result["all_issues"]:
print("Issue:", issue)
Common issues reported¶
Category |
Issue |
|---|---|
SPF |
No SPF record found |
SPF |
Multiple SPF records (RFC violation) |
SPF |
|
SPF |
Missing |
SPF |
Exceeds 10 DNS lookup limit (RFC 7208) |
DKIM |
No DKIM records found for any common selector |
DMARC |
No DMARC record found |
DMARC |
Policy |
DMARC |
No aggregate report address ( |
DMARC |
Policy applies to less than 100 % of messages ( |
security subdomains¶
Discover subdomains for a target domain using two complementary methods:
Certificate Transparency logs — queries the public crt.sh API for all certificates ever issued for the domain.
DNS brute-force — resolves prefixes from a built-in wordlist of 80+ common names (or a custom file) concurrently using a thread pool.
Each discovered subdomain is tagged with its discovery source.
nadzoring security subdomains [OPTIONS] DOMAIN
Options¶
Option |
Default |
Description |
|---|---|---|
|
built-in |
Path to a custom wordlist file (one prefix per line). Pass an empty string to skip brute-force entirely. |
|
|
Number of concurrent DNS resolution threads |
|
|
Per-host DNS resolution timeout in seconds |
|
off |
Skip DNS brute-force; use CT logs only |
Examples¶
# CT logs + built-in wordlist (default)
nadzoring security subdomains example.com
# CT logs only — faster, no DNS queries
nadzoring security subdomains --no-bruteforce example.com
# Custom wordlist, more threads, longer timeout
nadzoring security subdomains \
--wordlist /path/to/big-wordlist.txt \
--threads 100 \
--timeout 5 \
example.com
# Save results as JSON
nadzoring security subdomains -o json --save subdomains.json example.com
# Quiet mode for scripting
nadzoring security subdomains --quiet example.com
Python API¶
from nadzoring.security.subdomain_scan import scan_subdomains
# CT logs + built-in wordlist
results = scan_subdomains("example.com", max_threads=20, timeout=3.0)
for r in results:
print(f"{r['subdomain']:40} {r['ip']:16} [{r['source']}]")
# source: 'ct_log' | 'brute_force'
# CT logs only
results = scan_subdomains("example.com", wordlist_path="")
# Custom wordlist
results = scan_subdomains(
"example.com",
wordlist_path="/path/to/custom_wordlist.txt",
max_threads=50,
timeout=5.0,
)
# Filter by source
ct_found = [r for r in results if r["source"] == "ct_log"]
brute_found = [r for r in results if r["source"] == "brute_force"]
print(f"CT log: {len(ct_found)} Brute-force: {len(brute_found)}")
Built-in wordlist categories¶
The built-in wordlist of 80+ prefixes covers:
Common web services:
www,mail,ftp,smtpAdmin panels:
admin,portal,cpanel,whm,pleskAPIs and apps:
api,app,dev,staging,test,betaInfrastructure:
vpn,proxy,lb,waf,gateway,ns1,ns2CDN and static assets:
cdn,static,assets,media,imagesDevOps tooling:
git,gitlab,jenkins,ci,grafana,kibanaDatabases:
db,mysql,postgres,mongo,redis,elastic
security watch-ssl¶
Continuously monitor SSL/TLS certificates for one or more domains. On each check cycle the certificate is re-fetched and alerts are fired for:
Near expiry (
status == warning, fewer than--days-beforedays remain)Expired certificates (
status == expired)Certificate changes (expiry date differs from the previous cycle)
Check failures (connection error, parse error)
The command runs indefinitely until Ctrl-C, or for a fixed number of cycles
when --cycles is specified.
nadzoring security watch-ssl [OPTIONS] DOMAIN [DOMAIN ...]
Options¶
Option |
Default |
Description |
|---|---|---|
|
|
Seconds between full check cycles |
|
|
Number of cycles to run ( |
|
|
Days before expiry to trigger a warning alert |
Alert events¶
Trigger |
Message example |
|---|---|
Check failure |
|
Expired certificate |
|
Near expiry |
|
Certificate changed |
|
Examples¶
# Monitor one domain indefinitely (Ctrl-C to stop)
nadzoring security watch-ssl example.com
# Monitor multiple domains with a 14-day warning threshold
nadzoring security watch-ssl --days-before 14 \
example.com github.com cloudflare.com api.example.com
# Check every 5 minutes for a critical service
nadzoring security watch-ssl --interval 300 api.example.com
# Run 10 cycles with a 60-second interval, save all results
nadzoring security watch-ssl \
--cycles 10 --interval 60 \
-o json --save ssl_monitor_history.json \
example.com
# Quiet mode — suppress progress, emit only alert lines
nadzoring security watch-ssl --quiet --cycles 10 --interval 30 example.com
Python API¶
from nadzoring.security.ssl_monitor import SSLMonitor
monitor = SSLMonitor(
domains=["example.com", "github.com", "cloudflare.com"],
interval=3600, # seconds between cycles
days_before=14, # alert when fewer than 14 days remain
)
# Custom alert handler — integrate with Slack, PagerDuty, email, etc.
def on_alert(domain: str, message: str) -> None:
print(f"ALERT {domain}: {message}")
monitor.set_alert_callback(on_alert)
# Run a fixed number of cycles (blocking call)
results = monitor.run_cycles(cycles=5)
# Or run indefinitely until KeyboardInterrupt
try:
monitor.run()
except KeyboardInterrupt:
pass
# Inspect the full check history
for entry in monitor.history():
print(
entry["domain"],
entry["status"],
entry["remaining_days"],
entry["checked_at"],
)