-
Notifications
You must be signed in to change notification settings - Fork 2
Architecture and Design
Version: 3.0
Last Updated: April 2026
This page documents the internal architecture of the Linux Security Audit Project, including the v3.0 foundation library, audit pipeline, and module integration model.
The system is organised into three layers:
-
Modules (
modules/) — One file per security framework. Each module performs its own checks, returning a list ofAuditResultobjects. -
Shared Components (
shared_components/) — Common infrastructure used by all modules and the orchestrator: result objects, OS detection, caching, parallel execution, correlation registry, risk scoring, baseline comparison, remediation bundles, rollback generation. -
Orchestrator (
linux_security_audit.py) — Discovers modules, manages execution (sequential or parallel), aggregates results, runs the v3 audit pipeline, and produces reports.
+--------------------------------------------------------------------+
| linux_security_audit.py |
| - Argument parsing and command dispatch |
| - Module discovery and validation |
| - Sequential/parallel execution |
| - v3 pipeline invocation |
| - Report generation (HTML, JSON, CSV, XML, console) |
| - Remediation orchestration |
+----+----------------+--------------------+----------------+--------+
| | | |
v v v v
+----+----+ +-------+--------+ +-------+--------+ +---+--------+
| Modules | | shared_ | | shared_ | | reports/ |
| Core | | components/ | | components/ | | logs/ |
| CIS | | audit_common.py| | v3_pipeline.py | | |
| CISA | | (caching, /proc| | (correlation, | | |
| ENISA | | reads, AuditR.| | risk scoring, | | |
| ISO27001| | parallel exec)| | baseline diff)| | |
| NIST | +----------------+ +----------------+ +------------+
| NSA |
| STIG |
+---------+
The v3.0 release added eight new shared components alongside the existing audit_common.py. Each is designed to be importable and useful in isolation while wiring into the integrated pipeline through v3_pipeline.py.
| File | Purpose | Key Public Symbols |
|---|---|---|
correlation_registry.py |
Cross-framework control mappings |
get_correlations(), enrich(), register_correlation()
|
os_detection.py |
Distribution/family/kernel detection |
detect_os(), OSInfo, KernelVersion, family constants |
risk_scoring.py |
1-100 risk priority scoring |
compute_risk_score(), RiskScore, classify_*()
|
baseline_compare.py |
Drift detection between audit runs |
compare_to_baseline(), DriftReport, FindingDelta
|
remediation_bundles.py |
Predefined remediation groupings |
list_bundles(), get_bundle(), Bundle, ImpactProfile
|
rollback_generator.py |
Inverse change scripts |
RollbackGenerator, CaptureRecord
|
v3_pipeline.py |
High-level audit pipeline |
AuditPipeline, compute_compliance_scores(), export_json_v3()
|
Every check produces an AuditResult with these fields:
@dataclass(slots=True)
class AuditResult:
module: str # "CORE", "STIG", "CIS", etc.
category: str # "CIS 5.2 - SSH"
status: str # Pass/Fail/Warning/Info/Error
message: str # One-line check identifier
details: str # Multi-line technical detail
remediation: str # Shell command or guidance
severity: str # Critical/High/Medium/Low/Informational
cross_references: Dict[str, str] # Framework -> control_id mapping
timestamp: str # ISO 8601 capture timeThe orchestrator's pipeline enriches cross_references automatically via the correlation registry, so module authors only need to populate the field for module-specific topics not in the registry.
Detection runs once at orchestrator startup and is cached for the duration of the audit. Multiple sources are consulted in priority order:
-
/etc/os-release— systemd standard, present on essentially all modern distributions -
/usr/lib/os-release— immutable systems -
/etc/lsb-release— LSB standard, common on Ubuntu derivatives -
/etc/redhat-releaseand family-specific marker files - Fallback marker files (
/etc/debian_version,/etc/alpine-release, etc.) - uname-derived fallback (last resort)
The detected OSInfo object exposes:
- distro_id — lowercase identifier matching os-release ID (e.g. "ubuntu", "rhel", "rocky")
- distro_name — human-readable name
- version_id — version string
- version_codename — distribution codename (e.g. "jammy", "bookworm")
- family — canonical family code (Debian/RedHat/SUSE/Arch/Alpine/Gentoo/Slackware/Void/NixOS/Unknown)
- package_manager — detected canonical command for this distro
- init_system — systemd/openrc/runit/s6/dinit/sysvinit
- mac_framework — selinux/apparmor/tomoyo/smack/yama
- firewall — firewalld/ufw/nftables/iptables/shorewall
- container — docker/kubernetes/lxc/podman/systemd-nspawn (if running inside one)
- cloud_provider — aws/azure/gcp/digitalocean/linode/etc. (DMI inspection only, no network)
- architecture — x86_64/aarch64/armv7l/etc.
-
kernel — parsed
KernelVersionwithat_least(major, minor, patch)helper - eol — true if version is past end-of-life per bundled data
Modules should branch on family for broad logic (Debian-family vs Red Hat-family) and only branch on distro_id for distribution-specific quirks.
Debian family: Debian, Ubuntu, Linux Mint, Pop!_OS, elementary OS, Kali Linux, Zorin OS, MX Linux, Deepin, Parrot OS, Tails, Raspberry Pi OS, Devuan, KDE neon, Lubuntu, Xubuntu, Kubuntu, Ubuntu MATE, Ubuntu Budgie, antiX, siduction, BunsenLabs, Endless OS, LXLE, Peppermint, Qubes OS
Red Hat family: RHEL, CentOS, CentOS Stream, Fedora, Rocky Linux, AlmaLinux, Oracle Linux, Amazon Linux 2/2023, Scientific Linux, ClearOS, Springdale Linux, Circle Linux, Navy Linux, EuroLinux, MIRACLE LINUX, OpenELA
SUSE family: openSUSE Leap, openSUSE Tumbleweed, SUSE Linux Enterprise Server (SLES), SUSE Linux Enterprise Desktop (SLED), SLE HPC, GeckoLinux
Arch family: Arch Linux, Manjaro, EndeavourOS, Garuda Linux, ArcoLinux, Artix Linux, BlackArch, CachyOS, RebornOS, Obarun, Parabola
Independent: Alpine, Gentoo, Calculate Linux, Funtoo, Slackware, Salix, Void Linux, NixOS
The registry maps logical control topics (e.g. "ssh.permit_root_login") to their framework-specific identifiers (CIS 5.2.7, NIST AC-6(2), STIG V-230296, etc.). The current registry contains 135 topics covering the most common Linux security checks.
("ssh.permit_root_login", {
"CIS": "5.2.7",
"NIST": "AC-6(2)",
"STIG": "V-230296",
"ISO27001": "A.8.2",
"NSA": "SSH-1.3",
"CISA": "CPG-2.E",
"PCI-DSS": "8.2.1",
})When the orchestrator's pipeline runs, each result is enriched in this order:
- Module-supplied cross-references take highest precedence
-
Heuristic resolver scans
message,details, andcategoryfor keywords (e.g. "permitrootlogin" matchesssh.permit_root_login) - Registry lookup returns the full mapping for the matched topic
- Merge preserves module-supplied values; only fills in framework slots that the module didn't populate
This means a module can provide partial cross-references (e.g. just CIS) and let the registry fill in the others.
Mappings are sourced from publicly published official documentation:
- CIS Benchmarks for Linux v3.0.0 (Distribution Independent)
- NIST SP 800-53 Rev 5 control catalog
- ISO/IEC 27001:2022 Annex A
- DISA STIG for RHEL 9 V1R6, Ubuntu 22.04 V1R3
- PCI DSS v4.0.1
- HIPAA Security Rule §164.312
- GDPR Article 32
- NSA Network Infrastructure Security Guide
- CISA Cybersecurity Performance Goals v1.0.1
- ENISA Baseline Security Recommendations
The scoring engine produces a 1-100 risk priority for each Fail/Warning finding by combining four weighted components:
| Component | Weight | Values |
|---|---|---|
| Severity | 40% | Critical=40, High=30, Medium=20, Low=10, Informational=5 |
| Exploitability | 25% | KnownExploited=25, Remote=20, Local=12, Physical=4, NotExploitable=0 |
| Exposure | 20% | InternetFacing=20, DMZ=15, Internal=10, Isolated=5 |
| Asset Criticality | 15% | User-supplied 1-10, scaled to 0-15 |
The orchestrator infers exploitability from the finding text (KEV catalog references, service keywords, kernel keywords) and exposure from the OS detection result (cloud provider, container runtime, listening ports). Operators can override via --asset-criticality.
A Critical SSH PermitRootLogin finding on an internet-facing AWS host with criticality 9 yields:
Severity component: 40 (Critical)
Exploitability: 20 (Remote - SSH keyword)
Exposure: 20 (InternetFacing - AWS detected)
Criticality: 14 (9/10 * 15)
----
Total: 94 / 100
This same finding on an isolated build server with criticality 3 yields:
Severity component: 40 (Critical)
Exploitability: 20 (Remote)
Exposure: 5 (Isolated)
Criticality: 5 (3/10 * 15)
----
Total: 70 / 100
The 24-point spread reflects the contextual difference even though severity is identical.
The pipeline runs after all modules have executed and produced their AuditResult lists. It applies five phases in fixed order:
Module Results (raw)
|
v
+-----------------+
| 1. Validation | Normalise statuses, severities, sanitise text
+-----------------+
|
v
+-----------------+
| 2. Correlation | Apply cross-framework registry enrichment
+-----------------+
|
v
+-----------------+
| 3. Risk Scoring | Compute 1-100 priority for each Fail/Warning
+-----------------+
|
v
+-----------------+
| 4. Compliance | Simple, weighted, severity-adjusted scores
| Scoring | per-module and overall
+-----------------+
|
v
+-----------------+
| 5. Baseline | Optional drift comparison if --baseline supplied
| Diff |
+-----------------+
|
v
PipelineResult (final)
Each phase is idempotent and side-effect-free. The result of each phase is consumable by the report generators.
simple = passes / evaluated * 100
Where evaluated = total - errors. Errors mean the check could not run (e.g. service not installed) — they don't represent a failure of the system, so they're excluded from the denominator.
weighted = sum(severity_weight for r in passes) / sum(severity_weight for r in evaluated) * 100
Severity weights: Critical=5.0, High=3.0, Medium=2.0, Low=1.0, Informational=0.25.
sa = sum(severity_weight * status_credit for r in evaluated)
/ sum(severity_weight for r in evaluated) * 100
Status credits: Pass=1.0, Info=0.85, Warning=0.40, Fail=0.0, Error=0.0 (excluded).
This method best reflects operational risk because Warnings count partial credit while Fails count zero, weighted by severity.
Bundles group related correlation topics so an operator can apply a coherent set of fixes with a single command:
| Bundle | Topics | SSH Risk | Reboot |
|---|---|---|---|
| HardenSSH | 14 | ✓ | — |
| DisableLegacyProtocols | 3 | — | — |
| HardenKernel | 18 | — | — |
| EnableAuditLogging | 18 | — | ✓ |
| HardenAuthentication | 12 | — | — |
| LockDownNetwork | 5 | ✓ | — |
| SecureBootChain | 3 | — | ✓ |
| HardenSystemd | 3+ | — | — |
The orchestrator resolves a bundle name to its included topics, then to the specific findings in the current audit that match those topics, and applies their existing remediation commands. Bundles do not duplicate remediation logic; they're metadata describing which checks belong together.
When remediation runs, the orchestrator can capture pre-modification state and generate an inverse bash script. Capture types:
- File content + permissions — Base64-encoded snapshot for full restoration
- Sysctl values — Restore previous integer or remove drop-in line
-
Service state —
systemctl start/stopto restore previous active state -
Service enablement —
systemctl enable/disable/maskto restore boot behaviour -
Kernel module loading —
modprobeormodprobe -rbased on previous state
Generated scripts use set -euo pipefail, validate root privilege at start, log each operation, and process records in reverse order (LIFO). Output files are written 0700 (root-only) via atomic write-rename.
-
Module execution can run in parallel via
--parallel --workers N. Each module runs in its own thread with the shared cache (read-only after warm-up). - Pipeline phases run sequentially in the main thread. Phase 1 (validation) and Phase 2 (correlation) iterate over results and produce new lists.
-
Foundation module caches (correlation registry, OS detection, etc.) are guarded by module-level
threading.Lock()for thread-safe access during parallel module execution.
All output files are written with explicit safety properties:
-
Path traversal validation —
os.path.abspath()resolution, parent directory existence check, traversal pattern rejection - Atomic writes — write-to-temp-then-rename pattern; partial files never visible to consumers
- Permission setting — Reports written 0o600 (owner-only), logs written 0o644, rollback scripts written 0o700 (root-only executable)
-
Encoding — UTF-8 with
errors="replace"for tolerance of malformed system file content
- Development Guide — How to extend modules with new checks
- Output Reference — Report format specifications
- Framework Reference — Framework-specific details
Linux Security Audit Project · Version 2.0 · MIT License
Repository · Releases · Issues · Pull Requests
Changelog · Contributing · Security Policy · License
Frameworks: Core · CIS · CISA · ENISA · ISO 27001 · NIST · NSA · STIG
Coverage: 8 Modules · 1,207 Automated Security Checks · 5 Native Output Formats · Zero External Dependencies
This documentation reflects Linux Security Audit Project v2.0 released 2026-03-02. For older versions, see the release tags.
Version 2.0 · 8 modules · 1,207 checks
Frameworks Covered
Core · CIS · CISA · ENISA · ISO 27001 · NIST · NSA · STIG
Output Formats
HTML · JSON · CSV · XML · Console
Status Values
Pass · Fail · Warning · Info · Error
Severity Levels
Critical · High · Medium · Low · Informational