Concepts

Four-Layer Architecture

How StackSentry's six-module pipeline works and why the scanners are separated.

StackSentry assesses your web application across four distinct deployment layers simultaneously. Missing any one layer gives you an incomplete picture.


The Four Layers

┌─────────────────────────────────────────────────────────────┐
│                     Web Application                          │
│         Flask / Django / PHP / Any HTTP application          │
└──────────────────────────┬──────────────────────────────────┘
                           │ HTTP
┌──────────────────────────▼──────────────────────────────────┐
│                   Webserver (nginx / Apache)                  │
│         TLS config · Security headers · Rate limits          │
└──────────────────────────┬──────────────────────────────────┘
                           │ Container runtime
┌──────────────────────────▼──────────────────────────────────┐
│                    Docker Container                           │
│         User · Ports · Resource limits · Secrets             │
└──────────────────────────┬──────────────────────────────────┘
                           │ SSH
┌──────────────────────────▼──────────────────────────────────┐
│                      Linux Host                               │
│         SSH config · Firewall · Updates · Logging            │
└─────────────────────────────────────────────────────────────┘

A misconfiguration at any layer can compromise the rest. A hardened Flask application inside a Docker container with --privileged is still exploitable if the container is compromised.


Module Pipeline

Inside StackSentry, data flows through six modules:

Scanners → Checks → Scoring → Storage → Reporting → Remediation

Scanners

Five scanner classes collect raw data without making any security judgements:

ScannerData SourceUsed By
HttpScannerHTTP requests to target URLApp + webserver checks
SshScannerSSH commands via ParamikoHost checks + auto-fix
DockerScannerDocker SDK API queriesContainer checks
NginxScannernginx.conf static parsingWS-CONF-HSTS, WS-CONF-CSP
ComposeScannerdocker-compose.yml parsingContainer resource checks

Checks

24 pure Python functions. Each accepts a scanner object and returns a CheckResult:

@dataclass
class CheckResult:
    id:       str        # e.g. "APP-DEBUG-001"
    layer:    str        # app | webserver | container | host
    name:     str
    status:   Status     # PASS | FAIL | WARN | ERROR
    severity: Severity   # CRITICAL | HIGH | MEDIUM | LOW
    details:  str        # specific finding from this scan

Every check has guard clauses at the top — if the required context (SSH credentials, Docker host) is not available, it returns WARN immediately rather than crashing or producing misleading results.

Scoring

ScanResult aggregates all CheckResult objects and computes:

  • Pass rate (excluding infrastructure WARNs)
  • Letter grade (A–F)
  • Priority score per failing check
  • Attack path count
  • OWASP category breakdown

Storage

Every scan is persisted to ~/.stacksentry/history.db (SQLite). The DriftEngine compares the current scan against the previous one to surface regressions and improvements.

Reporting

The PdfGenerator produces a 14-section PDF report using ReportLab. JSON output is also available for CI/CD integration.

Remediation

Three levels of fix output:

  1. Static templates — pre-written shell scripts, Python/PHP code, nginx snippets
  2. LLM-generated patches — context-aware code via the Anthropic Claude API
  3. Auto-fix engine — applies fixes directly via SSH with validation

Why Separate Scanners from Checks?

This design means every check function is independently testable with a mock scanner object. No network connections are made during testing. The 321-test suite runs in 1.55 seconds because of this separation.

It also means you can run checks against locally provided configuration files without a live target — useful for CI/CD environments where you want to validate a deployment before it goes live.


Entry Point

The framework installs as a pip console script:

stacksentry = "sec_audit.cli:main"

This means stacksentry is available as a system command after pip install stacksentry — no need to navigate to a project directory or invoke Python directly.