Passive attack-surface visibility and client-ready security reports for small businesses.
Project description
Passive attack-surface radar for small businesses, agencies, and security consultants.
One safe scan turns a domain into a clear risk grade, structured JSON, and a client-ready report.
| Testing |
|
| Code quality |
|
| Code style |
|
| Package |
|
| Safety |
|
SentinelDeck inspects the public-facing posture of a domain across DNS, HTTP, TLS, email authentication, and its certificate-transparency footprint, using only the kind of normal lookups any browser or mail server would make. There is no intrusive scanning, no exploitation, and nothing a domain owner would not expect. The result is a risk score, an A to F grade, and a set of prioritised findings, each with a concrete copy-paste fix.
It is built for the people who need that picture fast: an agency qualifying a prospect, a consultant producing a client report, or a small team checking its own footprint.
Contents
- Features
- What it checks
- Installation
- Usage
- Example output
- How it works
- Development
- Safety model
- Support
- License
Features
Passive and safe by designOnly standard DNS, HTTP, TLS, and email lookups, the same requests any browser or mail server makes. Run it against any domain you are authorised to assess. |
Accurate, with a confidence modelDNS is resolved in-process and certificates are parsed directly. Any check that cannot be confirmed is marked unverified and kept out of the score, so a client never sees a guess presented as fact. |
Five surfaces in one passDNS hygiene, HTTP security headers, TLS certificate quality, email authentication, and domain registration intelligence, scored together into a single picture. |
Clear risk score and gradeEvery finding is weighted by severity into a 0 to 100 risk score and an A to F grade, each paired with a prioritised, plain-language remediation step. |
Copy-paste remediationEvery finding ships the exact fix, not just advice: the precise DNS record, HTTP header, or server config that resolves it, each with an authoritative reference. Carried in both the JSON and the HTML report. |
Interactive remediation simulatorThe HTML report lets a client tick off the fixes they plan to make and watch the projected score and grade climb live, with one-click "quick wins" that picks the shortest path to grade A. |
Attack-surface mappingReads certificate transparency logs to discover the domain's public subdomains, flags potentially sensitive names (dev, staging, admin, vpn), and detects dangling CNAMEs an attacker could take over. |
Monitoring and alertsDiff any two scans, or run the monitor command on a schedule to scan, compare against the last run, and post a webhook alert (Slack, Discord, or custom) the moment a domain's posture regresses. |
Report-ready outputsStructured JSON for automation, a polished dark and red HTML report for clients, a shareable score card, an embeddable grade badge, and an HTML change report. |
Resilient by designTwo certificate-transparency sources (crt.sh with a CertSpotter fallback) and a DNS-over-HTTPS fallback for blocked networks, so a scan keeps working where a naive tool would silently fail. |
What it checks
| Area | Checks |
|---|---|
| DNS | Resolution, CAA issuance control, DNSSEC |
| HTTP | HTTPS reachability, HTTP to HTTPS redirect, security-header presence and value quality, security.txt, cookie flags, version disclosure |
| TLS | Trust and failure reason (expired, self-signed, hostname mismatch, untrusted), expiry, protocol version, key strength, signature algorithm, hostname match |
| MX, SPF (policy, multiple records, 10-lookup limit), DMARC (policy, subdomain policy, enforcement coverage), DKIM, MTA-STS, TLS-RPT, BIMI | |
| Domain | Registrar, registration age, and expiry via RDAP |
| Subdomains | Public subdomain discovery via certificate transparency (crt.sh, CertSpotter), sensitive-name flagging, and dangling-CNAME takeover detection |
Every issue is scored by severity into a 0 to 100 risk score and an A to F grade.
Installation
SentinelDeck requires Python 3.10 or newer.
From PyPI (available once the first release is published, see RELEASING.md):
pip install sentineldeck
From source:
git clone https://github.com/sanmaxdev/SentinelDeck.git
cd SentinelDeck
python3 -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
Either way, this puts the sentineldeck command on your path. To verify:
sentineldeck --version
For development, install the dev extras (pytest and ruff):
pip install -e ".[dev]"
Usage
Scan a domain and write a JSON report:
sentineldeck scan example.com --output reports/example.json
Accept findings you have already reviewed so they stop affecting the score, by listing their ids in a suppressions file:
sentineldeck scan example.com --suppress .sentineldeck-ignore
Each line is a finding id (globs allowed, e.g. subdomain-takeover:*), and #
starts a comment. Accepted findings still appear under "Accepted" in the report
but are kept out of the risk score, so a known and accepted risk does not drag
the grade down on every re-scan.
Render a client-ready HTML report, a shareable score card, and a badge. The HTML report includes the attack-surface map and the interactive remediation simulator:
sentineldeck report reports/example.json \
--html reports/example.html \
--svg reports/example-card.svg \
--badge reports/example-badge.svg
Track how a domain's posture changes between two scans:
sentineldeck diff reports/example-may.json reports/example-june.json \
--html reports/example-change.html
The diff command shows what is new, what was resolved, score and grade
movement, and any severity escalations. It exits non-zero with --exit-code
when the posture regresses (a new high or critical finding, or a higher score),
so it drops straight into a cron job or CI step for scheduled monitoring.
Watch a domain on a schedule and get alerted when it regresses:
sentineldeck monitor example.com --webhook https://hooks.slack.com/services/...
The monitor command scans, compares against the previous run (stored under
.sentineldeck/ by default), and saves the new report as the latest, so a cron
job or scheduled task becomes a standing watch. With --webhook it posts an
alert (Slack, Discord, or any custom endpoint) when the posture regresses. The
first run establishes a baseline; use --alert-on change to hear about any
change, and --exit-code to fail a job on regression.
Useful flags: --pretty prints the full JSON to stdout, --timeout bounds the
HTTP and TLS probes, and diff --json or diff -o emit the structured delta.
Example output
{
"target": "example.com",
"risk_score": 27,
"grade": "B",
"findings": [
{ "id": "dmarc-missing", "severity": "medium", "confidence": "confirmed", "...": "..." }
]
}
How it works
src/sentineldeck/
├── scanner.py # runs every probe concurrently and assembles the report
├── scanners/ # one module per surface: dns, dns_hygiene, tls, http_headers,
│ # email_security, domain_intel, subdomains, takeover
├── risk/scoring.py # turns raw check results into scored findings
├── remediation.py # maps each finding to a concrete copy-paste fix
├── diff.py # compares two reports into a structured change delta
├── monitor.py # scan, compare to the last run, and persist state
├── alerts.py # webhook delivery on regression
├── reporters/ # json, html, svg (card + badge), and diff renderers
└── models.py # Finding and ScanReport data models
Each scanner is independent and keeps its network call injectable, so the whole suite is tested offline with mocked DNS, HTTP, and certificate-transparency data.
Development
pip install -e ".[dev]"
ruff check .
pytest -q
Optionally enable the pre-commit hooks so linting runs on every commit:
pip install pre-commit && pre-commit install
CI runs ruff and the full test suite on Python 3.10, 3.11, and 3.12, and CodeQL scans the codebase for security issues on every push.
Safety model
SentinelDeck is passive-first. It performs only normal DNS lookups and standard HTTP and TLS metadata requests against the supplied domain, plus public certificate-transparency queries. It does not probe, fuzz, or exploit anything. Use it only on domains you own or are authorised to assess.
Support
- Questions and bug reports: open an issue on the issue tracker.
- Security issues: please follow the security policy instead of filing a public issue.
- Contributing: see CONTRIBUTING.md. New checks must be passive-safe and come with tests. This project follows a Code of Conduct.
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sentineldeck-0.1.0.tar.gz.
File metadata
- Download URL: sentineldeck-0.1.0.tar.gz
- Upload date:
- Size: 65.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2cbcf3c00d10692587e8a6d39b05805632268de3f19a7f9d9492b9040045dd41
|
|
| MD5 |
6bea5f03818224a9d10122e0e0e612a5
|
|
| BLAKE2b-256 |
b00da8e49e824ad2f1e4ce737d56ca736f5f1d77d9f0cd5d44946ae6d8bc84db
|
Provenance
The following attestation bundles were made for sentineldeck-0.1.0.tar.gz:
Publisher:
publish.yml on sanmaxdev/SentinelDeck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sentineldeck-0.1.0.tar.gz -
Subject digest:
2cbcf3c00d10692587e8a6d39b05805632268de3f19a7f9d9492b9040045dd41 - Sigstore transparency entry: 1954612881
- Sigstore integration time:
-
Permalink:
sanmaxdev/SentinelDeck@9259213518223e767621674a7f238c67b4299fd9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sanmaxdev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9259213518223e767621674a7f238c67b4299fd9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file sentineldeck-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sentineldeck-0.1.0-py3-none-any.whl
- Upload date:
- Size: 57.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66e213a6a60772af388de061ac174c0d1a749c928cc39f1ec4adf30ff82a8332
|
|
| MD5 |
614976dbf2b8e710d9fe69814051afd2
|
|
| BLAKE2b-256 |
cc147a52287a992c8f394be60de2995cb5b15a2b1a2a723dabe57502f58f800f
|
Provenance
The following attestation bundles were made for sentineldeck-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on sanmaxdev/SentinelDeck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sentineldeck-0.1.0-py3-none-any.whl -
Subject digest:
66e213a6a60772af388de061ac174c0d1a749c928cc39f1ec4adf30ff82a8332 - Sigstore transparency entry: 1954612998
- Sigstore integration time:
-
Permalink:
sanmaxdev/SentinelDeck@9259213518223e767621674a7f238c67b4299fd9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sanmaxdev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9259213518223e767621674a7f238c67b4299fd9 -
Trigger Event:
release
-
Statement type: