Files
football/DeepReport-2026-05-08.md
reachableceo e80725005f docs: add deep audit report and honest STATUS.md update
DeepReport-2026-05-08.md: Full security audit with 39 findings
(6 CRITICAL, 9 HIGH, 12 MEDIUM, 7 LOW, 5 INFO).

STATUS.md: Updated to reflect actual audit state with honest
assessment of gaps. Removed inflated compliance claims. Added
remediation progress tracker.

Compliance claims acknowledged as aspirational by project owner.
Session 8 will focus on fixing all technical findings.

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
2026-05-08 11:49:44 -05:00

26 KiB

KNEL-Football Secure OS — Deep Security Audit Report

Date: 2026-05-08 Auditor: Senior Security Engineer / Technical Operations Manager Scope: Full codebase, build system, test suite, documentation, git history Classification: CONFIDENTIAL — For Owner Review Only


Executive Verdict: NOT PRODUCTION READY — DO NOT DEPLOY

Overall Risk Rating: 🔴 HIGH RISK

This system has 6 critical, 9 high, 12 medium, and 7 low severity findings across the codebase. The most damaging issues are:

  1. The encryption you're trusting your tier0 access to doesn't work as documented — Argon2id is not used; systems ship with PBKDF2
  2. The host FDE mandatory check that PRD FR-011 calls "cannot be bypassed" is never called — security theater
  3. USB devices can execute arbitrary code — missing noexec,nosuid,nodev on automount
  4. Secure Boot private keys are generated unencrypted — the root of trust is unprotected
  5. The test suite provides false confidence — ~85% of tests are grep pattern matching, not behavioral tests
  6. Compliance claims (CMMC L3, FedRAMP, ISO 27001) are fabricated — no organizational controls exist

The engineering shows real security thinking and honest effort. The JOURNAL.md is commendable. But the gap between documented claims and implemented reality is the project's primary risk. This system is not safe to deploy as tier0 infrastructure until all CRITICAL and HIGH findings are resolved.


Project Metrics (Measured)

Metric Value
Source scripts (src/) 3 files
Hook scripts (config/hooks/) 14 files
Test files (tests/) 26 files
Config files 7 files
Total lines (all source) ~8,357
ISO size 824 MB
ISO SHA256 df683e04a66f0fa69c6e2584e7d08913d0dde9367a347a2661ce120a464d0854
Build date 2026-05-07

Findings Summary

Severity Count Description
CRITICAL 6 System is fundamentally insecure; must fix before any deployment
HIGH 9 Significant security gaps; serious risk in production
MEDIUM 12 Important issues that weaken security posture
LOW 7 Minor issues; should fix but not blockers
INFO 5 Observations for improvement
Total 39

CRITICAL Findings (Must Fix Before Any Deployment)

C-01: Argon2id KDF NOT Actually Enforced — Systems Ship with PBKDF2

PRD Claim: FR-001 mandates "Argon2id key derivation" Reality: All installed systems use PBKDF2

  • config/includes.installer/preseed.cfg configures LUKS2 but has no option to set KDF type — Debian partman-crypto defaults to PBKDF2
  • config/hooks/installed/luks-kdf-configure.sh only creates a post-install helper script (/usr/local/bin/convert-luks-kdf.sh) for optional manual conversion
  • The helper is never auto-executed
  • encryption-setup.sh:89 falsely claims KDF: Argon2id in the README written to disk
  • luks-kdf-configure.sh:133 patches the README to say "run convert-luks-kdf.sh to enable" — admitting it's not enabled

Impact: PBKDF2 is significantly weaker than Argon2id against GPU-based brute force. An attacker with physical access to the encrypted disk has a much cheaper attack path than the PRD assumes.

Remediation: Add a post-install hook that automatically converts to Argon2id, or patch the initramfs-tools crypto config before the installer runs.


C-02: Host FDE Mandatory Check Is NEVER Enforced — PRD FR-011 Completely Violated

PRD Claim: FR-011 "No Bypass - This check cannot be disabled or bypassed" Reality: The check function exists but is never called

  • run.sh:47-118 defines check_host_fde() — comprehensive, well-written
  • run.sh:1049-1059 — the iso/iso:demo build path skips it entirely:
    log_warn "Host FDE check: ${KNEL_BUILD_MODE} build on potentially unencrypted host"
    log_warn "PRD FR-011 requires host FDE - proceeding with build anyway"
    
  • The function is defined, tested, documented, and completely inert
  • An unencrypted host means Secure Boot private keys, the ISO, and all build artifacts are written to plaintext storage

Impact: Build chain compromise. An attacker who compromises the unencrypted build host can inject malicious code into every ISO built on it.

Remediation: Call check_host_fde() at the top of the iso/iso:demo case block and exit 1 on failure.


C-03: Docker Build Runs --privileged With Full Host Access

File: run.sh:1065-1067

docker run --rm \
    --privileged \
    --user root \

--privileged grants the container: all devices, all kernel capabilities, mount permissions, seccomp/AppArmor bypass. Combined with --user root, a compromised build dependency or malicious hook script has full host root equivalence.

The Dockerfile correctly creates a non-root builder user (Dockerfile:67-76) and sets USER builder. The actual ISO build completely overrides this with --user root --privileged.

Impact: Container escape is trivial. Build supply chain compromise leads to host compromise.

Remediation: Replace --privileged with fine-grained capabilities: --cap-add SYS_ADMIN --cap-add MKNOD + specific device access for /dev/loop*.


C-04: Secure Boot Private Keys Generated Unencrypted (-nodes)

Files: run.sh:511-528, 762-777, 1141-1156

openssl req -new -x509 -newkey rsa:4096 -sha256 -days 3650 \
    -nodes -subj "/CN=KNEL-Football PK/" \
    -keyout "${SB_KEY_DIR}/PK.key" \

The -nodes flag generates private keys without passphrase encryption. PK, KEK, and db private keys — the root of trust for Secure Boot — are stored in plaintext on disk in tmp/secureboot-keys/. This code is duplicated three times in the codebase (any fix must be applied to all three).

Additionally, the key lifecycle is broken:

  • If config/secureboot-keys/ exists, the same keys are reused (good for consistency, but private keys could be in git)
  • If it doesn't exist, new keys are generated each build (previously deployed systems won't trust the new ISO)

Impact: An attacker who accesses the build host can extract PK.key, KEK.key, db.key and sign arbitrary bootloaders/kernels that will be trusted by every system that enrolled these keys.

Remediation: Generate keys once with a strong passphrase. Store in an HSM or at minimum a passphrase-protected PKCS#12. Never store unencrypted private keys on disk.


C-05: USB Automount Missing noexec,nosuid,nodev — Allows Code Execution from USB

File: config/hooks/live/usb-automount.sh:30-38

mount -t vfat -o rw,uid=1000,gid=1000,dmask=000,fmask=111 "${DEVICE}" "${MOUNT_BASE}"
mount -t ntfs-3g -o rw,uid=1000,gid=1000,dmask=000,fmask=111 "${DEVICE}" "${MOUNT_BASE}"
mount -t ext4 -o rw "${DEVICE}" "${MOUNT_BASE}"
mount -t auto -o rw,uid=1000,gid=1000 "${DEVICE}" "${MOUNT_BASE}"

PRD FR-008 explicitly requires "No automatic program execution" and "No device special files from USB". None of the mount commands include noexec, nosuid, or nodev. Additionally, dmask=000 makes all directories world-readable.

Impact: A BadUSB attack or malicious USB device can execute arbitrary binaries with setuid bits, bypassing all OS-level security controls. This is a well-known physical attack vector that the system claims to mitigate but doesn't.

Remediation: Add noexec,nosuid,nodev to all mount options. Change dmask=000 to dmask=077.


C-06: Plaintext Credentials in Git History (Permanent Exposure)

File: config/includes.installer/demo.preseed.cfg:38-45, 98-103

# football user: Kn3l-F00tball-D3m0!
d-i passwd/user-password-again string Kn3l-F00tball-D3m0!
d-i passwd/root-password-again string Kn3l-R00t-D3m0!
d-i partman-crypto/passphrase password Kn3l-D3m0-LUKS!

User password, root password, AND LUKS encryption passphrase are hardcoded in plaintext. This file is committed to git and the credentials are permanently in git history even if the file were deleted. If this repo is ever public or shared, these become exploitable.

The file says "DO NOT USE IN PRODUCTION" but there is no technical control preventing a demo ISO from being deployed to production. The iso:demo build path only prints a warning.

Also in TODO.md:22: Hardcode encryption passphrase: TestPassphrase2026!Secure — a future test passphrase documented in the backlog.

Impact: If demo ISOs are deployed (and nothing prevents this), the disk encryption is trivially bypassable with a publicly known passphrase.

Remediation:

  1. Use git filter-repo or BFG Repo-Cleaner to scrub credentials from history
  2. Add a build-time guard that refuses to build demo ISOs without an explicit --i-understand-this-is-insecure flag
  3. Rotate all credentials in demo.preseed.cfg

HIGH Findings (Serious Risk — Fix Before Production)

H-01: SSH StrictHostKeyChecking ask Allows MITM on First Connection

Files: src/security-hardening.sh:80, config/hooks/live/security-hardening.sh:60

PRD FR-006 says "strict host key checking". ask prompts the user but accepts unknown host keys by default, enabling MITM attacks. For a tier0 secure access terminal, this should be yes with pre-distributed known_hosts.


H-02: SSH Server Config Written Despite "Client Only" Requirement

Files: src/security-hardening.sh:87-114, config/hooks/live/security-hardening.sh:64-75

PRD FR-006: "No SSH server, no inbound SSH access". Yet sshd_config is generated and written to disk as "defense-in-depth." If openssh-server is ever installed (manually, via dependency, or through a supply chain attack), sshd will start with this configuration.


H-03: src/firewall-setup.sh Missing ct state established,related — Breaks WireGuard

File: src/firewall-setup.sh:26-49

The src/ firewall output chain does NOT include ct state established,related accept. Return traffic from WireGuard will be dropped by the default drop policy, breaking all VPN connectivity. The live hook version and install-scripts.sh version correctly include this rule. Three divergent implementations of the same firewall.


H-04: QR Code Scanner Leaks WireGuard Private Key via Insecure Temp File

File: config/hooks/live/qr-code-import.sh:26

mktemp creates a file that will contain the WireGuard private key. While the trap cleanup mitigates persistence, concurrent access during scan could leak the key. Additionally, the Python parser doesn't actually write the parsed config to /etc/wireguard/wg0.conf — the feature is non-functional.


H-05: Encryption Key Management Has Broken cryptsetup Syntax

File: config/hooks/installed/encryption-setup.sh:204

echo "$existing_pass" | cryptsetup luksAddKey /dev/sda3 <<< "$new_pass"

Uses BOTH pipe (echo |) and heredoc (<<<) simultaneously. Only one stdin source works. The pipe provides the existing passphrase, but <<< overwrites stdin with the new passphrase. This command may fail silently or expose passphrases in /proc/*/cmdline.


H-06: Hardcoded /dev/sda3 Device Path Throughout Encryption Scripts

Files: encryption-setup.sh:102,142,145,204,208,233,238, encryption-validation.sh:80

LUKS device hardcoded as /dev/sda3. NVMe drives (/dev/nvme0n1p3), virtio (/dev/vda3), or any other naming scheme causes silent failures. Only luks-kdf-configure.sh:41 correctly checks multiple device paths.


H-07: sbverify Returns Success Even When Verification Fails

File: run.sh:696-702, 860-866, 1252-1256

else
    log_warn "UKI signed but verification uncertain"
    return 0  # <-- STILL RETURNS SUCCESS
fi

UKI signature verification failure is non-fatal. The build proceeds as if signing succeeded. In a Secure Boot pipeline, this defeats the entire purpose.


H-08: Docker-Embedded UKI Build Missing module.sig_enforce=1

File: run.sh:843 (inside get_secureboot_script)

echo "quiet splash lockdown=confidentiality" > "$cmdline"

Missing module.sig_enforce=1 from the kernel command line. The main uki_build function (line 638) and inline hook (line 1229-1231) correctly include it. One of three code paths is missing a critical security parameter.


H-09: Build Cache Has No Integrity Verification

File: run.sh:1114-1121, 1289-1293

Docker volume cache stores bootstrap and package data between builds with no checksum or signature verification. An attacker with access to the Docker volume could inject modified packages that would be silently used in subsequent builds — a classic supply chain attack.


MEDIUM Findings

M-01: apply_security_hardening() Never Calls configure_fim() or configure_ssh_client()

File: src/security-hardening.sh:327-339

If src/security-hardening.sh is used directly, AIDE FIM and SSH client hardening are silently skipped. The live hook version includes them, creating divergent codebases.

M-02: Sudo Group Conflict — Overly Broad Access

File: config/hooks/installed/install-scripts.sh:222

usermod -a -G sudo football grants full sudo access (all commands), overriding the carefully crafted /etc/sudoers.d/99-knel-hardening that limits the user to specific commands.

M-03: PAM Not Configured for Password Enforcement

File: config/hooks/live/security-hardening.sh:78-97

Writing pwquality.conf alone does not enforce password requirements. PAM must be configured to use pam_pwquality.so in /etc/pam.d/common-password, which is never modified by any hook. The password policy is inert.

M-04: Recovery Key Stored in Plaintext

File: config/hooks/installed/encryption-setup.sh:238

Recovery key written to /var/backups/keys/ as plaintext. PRD FR-001 states "No plaintext keys stored anywhere on the system."

M-05: Firewall Allows WireGuard to Any Endpoint

File: config/hooks/live/firewall-setup.sh:54

Live system allows UDP to ports 51820-51830 to any IP, contradicting PRD FR-004's "configured endpoints only." The install-scripts.sh version correctly locks to specific endpoint IPs.

M-06: AIDE Database Never Initialized

File: config/hooks/live/security-hardening.sh:99-132

AIDE configuration is written but aideinit is never run. No database exists, no cron/timer runs checks. File integrity monitoring is non-functional.

M-07: Mount Hardening Only Applies to Existing fstab Entries

File: config/hooks/installed/mount-hardening.sh:23-43

Only hardens entries that already exist in /etc/fstab. For a fresh LUKS+LVM install, /tmp and /home may not have separate entries.

M-08: USB Automount Has No Audit Logging

File: config/hooks/live/usb-automount.sh

PRD FR-008 requires audit logging of USB insertion/removal. No logger command, no auditd rule. The script writes to stdout only.

M-09: Build Not Reproducible

File: run.sh:1078-1318

No SOURCE_DATE_EPOCH, no fixed mirror snapshots, no .buildinfo. Two builds at different times produce different ISOs. PRD FR-010 claims "reproducible builds."

M-10: No GPG Signing of ISO Artifacts

PRD DEP-001 requires "GPG signature verification." QA-003 requires "Signed release artifacts." No GPG signing is implemented anywhere.

M-11: Base Image Not Digest-Pinned

File: Dockerfile:7

FROM debian:13.3-slim AS base

Docker Hub can serve different image content for the same tag. Should use @sha256:<digest>.

M-12: WiFi Blacklist Incomplete vs PRD

File: src/security-hardening.sh:9-30

Missing rtl8xxxu, iwlmvm, brcmsmac, brcm80211, ath10k_sdio, ath11k* — modern drivers not covered by the blacklist.


LOW Findings

ID Issue Location
L-01 Serial console enabled in GRUB for all builds config/bootloaders/grub-pc/config.cfg:4-7
L-02 Production preseed enables root login config/includes.installer/preseed.cfg:43
L-03 KexAlgorithms includes legacy DH group exchange src/security-hardening.sh:70
L-04 VNC has no authentication (localhost only) vm/template.xml:42-44
L-05 KNEL_BUILD_MODE can be spoofed via environment run.sh:1076
L-06 Hooks path inside repo tree (injectable by committers) scripts/setup-githooks.sh:32
L-07 Build log at predictable /tmp path (symlink attack) run.sh:15

INFO Findings

ID Issue
I-01 Protocol 2 in sshd_config is redundant (OpenSSH 7.0+)
I-02 Kernel headers included in build-iso.sh (unnecessary)
I-03 AIDE uses md5 in addition to sha256/sha512 (unnecessary)
I-04 --win32-loader true in build (unnecessary for secure OS)
I-05 user.max_user_namespaces = 100 is generous for single-user system

Test Suite Assessment: 🔴 FALSE CONFIDENCE

Test Quality Breakdown

Category Percentage Assessment
grep pattern matching (not behavioral) ~85% Verifies text exists, not that it works
Behavioral tests (source + execute) ~10% Only in *_comprehensive_test.bats files
Always-pass tautologies (` true, skip`)

Critical Test Deficiencies

  1. Zero negative/adversarial testing: No test verifies that bad things are rejected (wrong passwords, weak passphrases, unauthorized access)
  2. Zero runtime verification: All VM/system tests are skip stubs. No CI pipeline runs them against a real ISO.
  3. Tautological tests that always pass:
    • usb-automount_test.bats:181: true — does nothing
    • execution_comprehensive_test.bats:39-54: All loops use || true
    • hooks_comprehensive_test.bats:121-155: All "security" tests use || true
  4. Assertions too broad: grep -q "512" matches line numbers, comments, anything
  5. ~40-50% test duplication: Same checks copy-pasted across 5-9 files
  6. Pre-commit hook only runs unit tests: Integration, security, and system tests are NOT run before commit
  7. Hook changes bypass coverage check: Adding config/hooks/installed/backdoor.sh would pass pre-commit if config_test.bats exists

Missing Test Categories (None Exist)

  • Cryptographic validation (cipher strings, key sizes)
  • Secure Boot chain validation (PK→KEK→db hierarchy)
  • Preseed syntax validation
  • nftables syntax validation (nft -c -f)
  • Sysctl parameter validity
  • Idempotency testing
  • Build reproducibility
  • Supply chain integrity
  • Privilege escalation prevention
  • Network isolation verification

Documentation Assessment: ASPIRATIONAL, NOT ACCURATE

Compliance Claims vs Reality

Claim File Reality
CMMC Level 3 COMPLIANCE.md:12 Fabricated — requires 130+ practices, 3PAO assessment, organizational controls
FedRAMP LI-SaaS COMPLIANCE.md:13 Fabricated — requires agency sponsorship, 3PAO, ConMon
ISO/IEC 27001:2013 VERIFICATION-REPORT.md:377 Meaningless — organizational certification, not a codebase property
DISA STIG COMPLIANCE.md:14 Adapted — uses RHEL STIG IDs on Debian; no Debian 13 STIG exists
NIST SP 800-53 COMPLIANCE.md Partial — maps ~12 controls; 800-53 has 1,000+
FIPS 140-2 PRD CR-002 Claimed — no FIPS-validated modules, uses /dev/urandom for keys

Documentation Contradictions

  • VERIFICATION-REPORT.md contains two different checksums and two different build times
  • encryption-setup.sh:89 claims KDF: Argon2id — actually PBKDF2
  • COMPLIANCE.md:85 references /usr/local/bin/knel-compliance-check.shfile does not exist
  • JOURNAL.md:444-446 references three hook files that don't exist
  • VERIFICATION-REPORT.md:26 references config/preseed.cfg — wrong path

PRD Compliance Matrix

Requirement Status Gap
FR-001: LUKS2 FDE (Argon2id) NOT MET Ships with PBKDF2
FR-002: Debian 13 Base MET
FR-003: Desktop Environment MET
FR-004: Network Isolation PARTIAL Live firewall allows any WG endpoint
FR-005: Hardware Disabled MET WiFi/BT blacklists present
FR-006: SSH Client Only PARTIAL StrictHostKeyChecking ask not yes; sshd_config written
FR-007: System Hardening PARTIAL PAM not enforced; sudo group conflict
FR-008: USB Handling NOT MET Missing noexec,nosuid,nodev; no audit logging
FR-009: Immutability MET
FR-010: ISO Build (Reproducible) NOT MET No reproducibility controls
FR-011: Host FDE Mandatory NOT MET Check exists but never called
FR-012: Secure Boot/UKI PARTIAL Keys unencrypted; one build path missing module.sig_enforce

PRD Compliance: 3/12 fully met, 5/12 partially met, 4/12 not met


Git History Assessment

Category Status Finding
Commit format Good Conventional commits with verbose bodies
Atomic commits Violated 13 fixes in single commit 62d2060
Branch protection Missing Direct push to main; no CODEOWNERS; no CI
Secret exposure Critical Plaintext passwords permanently in history
Build artifacts Clean No ISOs/binaries committed
Pre-commit enforcement ⚠️ Partial Opt-in only; not server-side

Phase 1 — Blockers (Must fix before ANY deployment)

# Finding Effort Impact
1 Enforce Argon2id KDF automatically (C-01) Medium Fixes encryption strength
2 Call check_host_fde() in build path (C-02) Trivial Enforces supply chain security
3 Add noexec,nosuid,nodev to USB mounts (C-05) Trivial Prevents BadUSB attacks
4 Encrypt Secure Boot private keys (C-04) Medium Protects boot chain trust
5 Remove --privileged from Docker build (C-03) Medium Prevents container escape
6 Scrub credentials from git history (C-06) Medium Prevents credential exposure

Phase 2 — Critical Hardening (Before production use)

# Finding Effort
7 Fix StrictHostKeyChecking yes (H-01) Trivial
8 Remove sshd_config generation (H-02) Trivial
9 Fix sbverify to fail on error (H-07) Trivial
10 Add module.sig_enforce=1 to all UKI paths (H-08) Trivial
11 Fix sudo group conflict (M-02) Trivial
12 Configure PAM for password enforcement (M-03) Small
13 Initialize AIDE database (M-06) Small
14 Add GPG signing to ISO artifacts (M-10) Small
15 Enable GitHub branch protection Trivial

Phase 3 — Test Suite Overhaul (Before trusting the test results)

# Finding Effort
16 Rewrite tests as behavioral, not grep-based Large
17 Add negative/adversarial testing Large
18 Remove tautological tests (`
19 Add CI pipeline with VM boot testing Large
20 Deduplicate test suite Medium

Phase 4 — Documentation Cleanup

# Finding Effort
21 Remove fabricated compliance claims Small
22 Fix VERIFICATION-REPORT contradictions Small
23 Remove phantom file references Small
24 Add threat model document Medium

Positive Findings (What's Done Well)

  1. JOURNAL.md is genuinely excellent — 13 proper ADRs, honest self-criticism, append-only discipline
  2. Package pinning in Dockerfile — All build dependencies pinned to specific versions
  3. .gitignore is comprehensive — No build artifacts or secrets committed
  4. Security hardening coverage is broad — Kernel, sysctl, services, mount, sudo, audit all addressed
  5. SDLC process is well-documented — Even if enforcement is incomplete, the process is sound
  6. Pre-commit hook exists — Opt-in but provides a foundation for enforcement
  7. Defense-in-depth thinking — Multiple layers of security controls throughout
  8. No binary artifacts in git — Clean separation of source and output
  9. Wifi/BT blacklisting — Comprehensive module blacklists for wireless hardware
  10. Immutable package managementdisable-package-management.sh properly locks down apt/dpkg

Final Assessment

Is This Production Ready for Tier0 Infrastructure?

No.

The project demonstrates real security engineering skill and honest effort. The architecture is sound in principle. But the implementation has critical gaps between documented claims and actual behavior that would be unacceptable for a system protecting tier0 infrastructure access.

The most dangerous aspect is false confidence: the test suite says 786 tests pass, the verification report says everything is , and the compliance matrix claims CMMC L3 / FedRAMP compliance. None of these are accurate. An operator deploying this system based on these assurances would believe they are protected when they are not.

Specifically, as a tier0 access terminal:

  • The disk encryption uses a weaker KDF than documented
  • USB devices can execute arbitrary code
  • The build chain can be compromised via the unencrypted build host
  • Secure Boot keys are unprotected
  • There are no behavioral tests proving any security property actually works
  • The compliance framework is aspirational documentation, not verified implementation

Estimated Effort to Production-Ready

Phase Effort Timeline
Phase 1 (Blockers) ~40 hours 1-2 weeks
Phase 2 (Hardening) ~30 hours 1-2 weeks
Phase 3 (Test overhaul) ~60 hours 2-3 weeks
Phase 4 (Docs cleanup) ~20 hours 1 week
Total ~150 hours 5-8 weeks

Recommendation

Do not deploy. Fix Phase 1 blockers first. Then do a full end-to-end test: build the ISO, install on real hardware, verify encryption parameters with cryptsetup luksDump, attempt a BadUSB attack, verify the firewall actually blocks non-VPN traffic, and attempt privilege escalation. Only deploy after hands-on verification confirms the security properties work as documented.


Report generated: 2026-05-08 Auditor: Senior Security Engineer / Technical Operations Manager Review classification: CONFIDENTIAL