StackSentry produces a letter grade (A–F) and a prioritised remediation roadmap for every scan. This page explains exactly how both are calculated.
The Grade Scale
| Grade | Score Range | What it Means |
|---|---|---|
| A | ≥ 90% | Excellent — minimal outstanding issues |
| B | 80–89% | Good — a few non-critical items to address |
| C | 70–79% | Acceptable — some meaningful gaps to close |
| D | 60–69% | Poor — material risk requiring prompt attention |
| F | < 60% | Failing — significant misconfigurations present |
Security grading is conservative. A 70% pass rate means roughly one in three checks is failing. In a production security context that represents real, unacceptable risk — which is why 70% earns a C, not a pass.
Pass Rate Calculation
The pass rate is the percentage of checks returning PASS, with two categories excluded from the denominator:
1. ERROR status — indicates the check itself failed to run (network error, permission denied), not a security finding.
2. Infrastructure WARNs — checks from the host or container layers that returned WARN solely because the required credentials (SSH or Docker) were not provided. A PHP shared hosting application should not be penalised for lacking SSH access.
eligible = [c for c in checks
if c.status != Status.ERROR
and not is_infrastructure_warn(c)]
pass_rate = len([c for c in eligible if c.status == Status.PASS]) / len(eligible)
Priority Score Formula
Every failing check is assigned a priority score to determine which phase of the remediation roadmap it belongs to:
priority_score = (severity_score × impact_weight) ÷ effort_score
Severity Score
Derived from the OWASP risk rating methodology:
| Severity | Score |
|---|---|
| CRITICAL | 4.0 |
| HIGH | 3.0 |
| MEDIUM | 2.0 |
| LOW | 1.0 |
Impact Weight
A float between 0.5 and 2.0 reflecting the expected security risk reduction if this check passes. Defined per check in sec_audit/config.py.
Effort Score
A float between 0.5 and 2.0 reflecting the implementation cost:
| Effort | Score | Example |
|---|---|---|
| LOW | 0.5 | One configuration flag change |
| MEDIUM | 1.0 | Moderate configuration change |
| HIGH | 2.0 | Architectural change or rebuild |
Example Calculation
APP-DEBUG-001 — disabling Flask debug mode:
severity_score = 3.0 (HIGH)
impact_weight = 2.0 (significant risk reduction)
effort_score = 0.5 (one config flag: DEBUG=False)
priority_score = (3.0 × 2.0) ÷ 0.5 = 12.0 → Day 1
Compare to a MEDIUM check requiring a container rebuild:
priority_score = (2.0 × 1.0) ÷ 2.0 = 1.0 → Day 30
Same importance on paper — but the effort difference means the first fix should happen today and the second can wait.
The 30-Day Roadmap
Checks are sorted by descending priority score and assigned to three phases:
| Phase | Proportion | Timing |
|---|---|---|
| Day 1 | Top 30% of priority scores | Fix immediately |
| Day 7 | Next 40% | Fix this week |
| Day 30 | Remaining 30% | Planned backlog |
The roadmap is produced automatically in both the CLI output and the PDF report.
What-If Simulation
You can project your grade after applying specific fixes without changing anything:
stacksentry -t https://your-app.com \
--simulate HOST-SSH-001,WS-HSTS-001,WS-SEC-001
The simulator creates a temporary copy of the scan result, marks the specified checks as PASS, and recomputes all metrics. Nothing is persisted.
Current: F (45.5%) — 1 attack path
Simulated: C (72.7%) — 0 attack paths
This answers the question “which three fixes get us out of F?” before you touch the server.