Files
command-center/omp-docs/reports/fleet-security-audit-2026-10-21.html
T
Frank 27da5cd9ec docs(reports): land the fleet security audit with its per-host vuln passes
Fold the Dankclaw and Dankserver vulnerability passes into
fleet-security-audit-2026-10-21.html: the stub "Advisory cross-reference (in
progress)" section becomes the full matrix (host advisories, GHSA coverage,
image-vulnerability matrix, no-advisory census, observed-without-credentials
rows for the two livingroom hosts) and the header links the two working files,
which move into omp-docs/reports/ with an index of their own.

Correct three figures the audit had wrong, all found by re-probing: the
mutable-tag census (17 -> 19 Dankclaw manifests / 17 unique references, +4 on
Dankserver), the Dankserver OpenSSH advisory count (0 -> 5 unpatched CVEs; the
first OSV query omitted the version epoch, and OSV answers "0 vulns" rather
than "unknown" for a malformed purl), and the Plex version ("12.1.0" is
Jellyfin's - the live container reports 1.43.5.11029-6bf8af3f0-ls329). Also
repair a malformed <code> tag in F1's evidence cell.

kb-lint and kb-coverage both report 0 issues; index.md gains the Reports
section and log.md the matching entry.
2026-10-21 14:04:33 -07:00

501 lines
56 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fleet Security Audit — 2026-10-21</title>
<style>
:root{
--primary:#2563eb; --secondary:#64748b; --success:#16a34a; --warning:#ca8a04;
--danger:#dc2626; --background:#f8fafc; --card:#ffffff; --border:#e2e8f0;
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Ubuntu,sans-serif;
line-height:1.6;background:var(--background);color:#1e293b}
header{background:linear-gradient(135deg,var(--primary),#1e40af);color:#fff;padding:2rem 1rem;text-align:center}
header h1{font-size:1.75rem;font-weight:600;margin-bottom:.5rem}
header .subtitle{opacity:.9;font-size:.95rem}
header .date{margin-top:.75rem;font-size:.85rem;opacity:.8}
.container{max-width:1080px;margin:0 auto;padding:1.5rem}
section{background:var(--card);border-radius:12px;padding:1.5rem;margin-bottom:1.5rem;box-shadow:0 1px 3px rgba(0,0,0,.08)}
section h2{color:var(--primary);font-size:1.25rem;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:2px solid var(--border)}
h3{font-size:1rem;color:#334155;margin:1.25rem 0 .75rem;font-weight:600}
h3:first-child{margin-top:0}
p{margin-bottom:.75rem;color:#475569}
ul,ol{margin:.75rem 0 .75rem 1.25rem;color:#475569}
li{margin-bottom:.5rem}
code{font-family:'SF Mono',Monaco,'Cascadia Code',monospace;background:#f1f5f9;padding:.15rem .4rem;border-radius:4px;font-size:.9em;color:#0f172a}
pre{background:#1e293b;color:#e2e8f0;padding:1rem;border-radius:8px;overflow-x:auto;margin:.75rem 0;font-size:.85rem;line-height:1.5}
pre code{background:transparent;padding:0;color:inherit}
table{width:100%;border-collapse:collapse;margin:1rem 0;font-size:.9rem}
th,td{padding:.7rem .75rem;text-align:left;border-bottom:1px solid var(--border);vertical-align:top}
th{background:#f1f5f9;font-weight:600;color:#334155;font-size:.8rem;text-transform:uppercase;letter-spacing:.04em}
tbody tr:hover{background:#f8fafc}
.sev{font-size:.72rem;font-weight:700;padding:.2rem .55rem;border-radius:20px;text-transform:uppercase;letter-spacing:.04em;white-space:nowrap}
.sev.critical{background:#fee2e2;color:#991b1b}
.sev.high{background:#ffedd5;color:#9a3412}
.sev.medium{background:#fef3c7;color:#92400e}
.sev.low{background:#dbeafe;color:#1e40af}
.sev.info{background:#e2e8f0;color:#475569}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:1rem;margin:1rem 0}
.card{background:var(--background);border-radius:8px;padding:1rem;border-left:4px solid var(--secondary)}
.card.critical{border-left-color:var(--danger)}
.card.ok{border-left-color:var(--success)}
.card.warning{border-left-color:var(--warning)}
.card h4{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--secondary);margin-bottom:.4rem}
.card .value{font-size:1.35rem;font-weight:700;color:#1e293b}
.card .value.error{color:var(--danger)}
.card .value.warn{color:var(--warning)}
.card .value.good{color:var(--success)}
.tag{display:inline-block;font-size:.72rem;padding:.1rem .45rem;border-radius:4px;background:#eef2ff;color:#3730a3;margin-right:.25rem}
.tag.pin{background:#dcfce7;color:#166534}
.tag.mutable{background:#fee2e2;color:#991b1b}
.tag.loop{background:#e2e8f0;color:#475569}
.note{background:#fffbeb;border-left:4px solid var(--warning);padding:.9rem 1rem;border-radius:6px;margin:1rem 0;font-size:.9rem;color:#78350f}
.verdict{background:#f0f9ff;border-left:4px solid var(--primary);padding:.9rem 1rem;border-radius:6px;margin-bottom:1rem;font-size:.95rem}
figure{margin:1rem 0}
figcaption{font-size:.8rem;color:var(--secondary);margin-top:.4rem;text-align:center}
footer{text-align:center;font-size:.8rem;color:var(--secondary);padding:1rem 0 2rem}
@media print{body{background:#fff}section{box-shadow:none;border:1px solid var(--border)}}
</style>
</head>
<body>
<header>
<h1>Fleet Security Audit</h1>
<div class="subtitle">blankpad · Dankclaw · Dankserver · LAN edge (192.168.0.0/24)</div>
<div class="date">Audited 2026-10-21 · Comrade Chief Designer, Soviet Computer Systems of Frank</div>
<div class="date">Per-host vulnerability passes: <a href="vuln-dankclaw.md">vuln-dankclaw.md</a> · <a href="vuln-dankserver.md">vuln-dankserver.md</a></div>
</header>
<div class="container">
<section id="verdict">
<h2>Verdict</h2>
<div class="verdict">
No compromise indicators. The fleet is not patched-and-probed enough to notice a breach, and four
findings are one config line each: a shared SSH password that is also in plaintext everywhere it
was echoed, <strong>23 container images on floating tags</strong>, Gitea accepting
<strong>self-registration with public read</strong>, and no HSTS/CSP on the edge proxy.
</div>
<div class="grid">
<div class="card critical"><h4>Critical</h4><div class="value error">1</div></div>
<div class="card warning"><h4>High</h4><div class="value warn">2</div></div>
<div class="card warning"><h4>Medium</h4><div class="value warn">4</div></div>
<div class="card"><h4>Low / info</h4><div class="value">3</div></div>
<div class="card ok"><h4>Rootkits</h4><div class="value good">none</div></div>
</div>
<p><strong>Coverage.</strong> Three boxes audited with credentials (blankpad, Dankclaw, Dankserver);
four more observed without access (router <code>.1</code>, <code>.40</code>/<code>.215</code> =
danklivingroom, <code>.75</code> = Apple device). Every claim below carries the command that produced
it; three claims inherited from an earlier survey were <strong>refuted</strong> and are listed in
<a href="#caveats">Caveats</a> rather than repeated.</p>
</section>
<section id="method">
<h2>Scope and method</h2>
<table>
<thead><tr><th>Instrument</th><th>Version</th><th>What it proved</th></tr></thead>
<tbody>
<tr><td>nmap (NSE)</td><td>7.98</td><td>TCP/UDP service and banner census, TLS certs, <code>ssh2-enum-algos</code>, <code>sshvulns.nse</code> on every reachable address; <code>-sn</code> sweep of 192.168.0.0/24.</td></tr>
<tr><td>masscan</td><td>1.3.2</td><td>Full 1–65535 sweep of all live hosts (source-pinned to the Wi-Fi NIC), 65 535 ports per host, 78 open TCP ports total.</td></tr>
<tr><td>fping</td><td>5.3</td><td>27 live addresses from ARP+ICMP; reconciled against the KB network page.</td></tr>
<tr><td>lynis</td><td>3.1.5</td><td>Host audit on blankpad (71 warnings, see <a href="#blankpad">blankpad</a>).</td></tr>
<tr><td>checksec</td><td>2.7.1</td><td>Binary hardening of <code>sshd</code>, <code>ssh</code>, <code>sudo</code> on blankpad.</td></tr>
<tr><td>OSV API</td><td>—</td><td>Advisory lookup for pinned versions (distro ecosystems + Go/npm/PyPI for containers). In progress, see <a href="#cve">Cross-reference</a>.</td></tr>
<tr><td>direct inspection</td><td>—</td><td><code>sshd -T</code>, <code>authorized_keys</code> counts, host-key dates, quadlet manifests, live service configs, package/update state, and <code>ss -tlnp</code> as root on every box (root-owned sockets are invisible to an unprivileged <code>ss</code>).</td></tr>
</tbody>
</table>
<h3>In scope / out of scope</h3>
<ul>
<li><strong>Audited with credentials:</strong> blankpad (CachyOS laptop, the repo's home), Dankclaw (Ubuntu 26.04 services box), Dankserver (Ubuntu 26.04 + 2× R9700 inference box).</li>
<li><strong>Observed only:</strong> <code>.40</code>/<code>.215</code> (danklivingroom, Ubuntu 24.04.4 — no key installed, banner-level only), <code>.75</code> (Apple device), router <code>.1</code> (ARRIS admin UI).</li>
<li><strong>Deliberately untouched:</strong> no service restarts, no package installs on the servers, no <code>/etc</code> edits anywhere — this pass is read-only; fixes are proposed in <a href="#fixes">Remediation</a> and land as their own changes.</li>
</ul>
</section>
<section id="findings">
<h2>Findings register</h2>
<table>
<thead><tr><th>Sev</th><th>Where</th><th>Finding</th><th>Evidence</th><th>Fix</th></tr></thead>
<tbody>
<tr>
<td><span class="sev critical">critical</span></td>
<td>all 3 boxes</td>
<td><strong>One SSH/sudo password for the whole fleet, and it is in plaintext in shell history, agent transcripts and command lines.</strong> All three boxes still accept it as an authentication factor (<code>PasswordAuthentication yes</code>), so a leaked transcript downgrades key-only SSH to a guessed secret.</td>
<td><code>sshd -T</code> on blankpad, Dankclaw, Dankserver → <code>passwordauthentication yes</code>, <code>pubkeyauthentication yes</code>, <code>permitrootlogin prohibit-password</code>, <code>maxauthtries 6</code>. Every privileged probe in this audit ran <code>printf '&lt;pw&gt;' | sudo -S</code>, which also puts the secret in the process table (<code>/proc/&lt;pid&gt;/cmdline</code> is world-readable) — the same class of leak that previously exposed an HF token.</td>
<td>Rotate the password once, then set <code>PasswordAuthentication no</code> in a drop-in on all three boxes and switch agent-side privilege escalation to <code>sudo -n</code> (already passwordless on the servers) or <code>sudo -S &lt; ~/.secrets/sudo-pass</code> with mode <code>600</code>. Verify keys in a second session before closing the door.</td>
</tr>
<tr>
<td><span class="sev high">high</span></td>
<td>Dankclaw, Dankserver</td>
<td><strong>23 container images run mutable tags</strong> — 19 of the 33 quadlet manifests on Dankclaw (17 unique references: 15 × <code>:latest</code>, 1 × <code>:main</code>, 1 × <code>:nightly</code>) and 4 of the 12 on Dankserver. The deployed version cannot be read from the manifest, a restart can silently upgrade a production service, and a CVE lookup is impossible without inspecting each container.</td>
<td><code>grep -h '^Image=' ~/.config/containers/systemd/*.container</code> on both hosts. Dankclaw, recounted from the manifests: 33 <code>Image=</code> lines — 19 mutable (15 × <code>:latest</code>, 1 × <code>:main</code>, 1 × <code>:nightly</code>, the rest duplicate declarations of <code>localhost/hermes-agent:latest</code>), 10 exact-tag, 4 digest-pinned. The Dankclaw working page reports 24 there because it also counts rolling release tags (<code>postgres:16-alpine</code> ×2, <code>valkey:9-alpine</code>, <code>comfyui-rocm:gfx1151</code>) and <code>open_notebook:v1-latest@sha256…</code> as mutable. Dankserver: 4 on <code>:latest</code> plus the rolling <code>mariadb:11</code> and <code>redis:7-alpine</code>. Four Dankclaw images <em>do</em> pin digests (<code>open_notebook:v1-latest@sha256:54b2025…</code>, <code>surrealdb:v2@sha256:e5d7387…</code>, <code>chromedp/headless-shell@sha256:2d349b5…</code>, <code>ghcr.io/goauthentik/ldap@sha256:2e7b259…</code>), so the policy exists but is applied inconsistently. Live probes disagree with the tags: <code>gitea:latest</code> → 1.27.3, <code>grafana:latest</code> → 13.2.2 (commit <code>1bea008</code>), <code>jellyfin:latest</code> → 12.1.0, <code>pihole:latest</code> → Core v6.4.3 (vendor v6.5).</td>
<td>Pin every <code>Image=</code> to <code>tag@sha256:digest</code> (or at minimum an exact tag) in the quadlet manifests, one commit per host; see <a href="#images">Image census</a>.</td>
</tr>
<tr>
<td><span class="sev high">high</span></td>
<td>Dankclaw</td>
<td><strong>Gitea allows self-registration and unauthenticated read.</strong> The instance carries the fleet's infrastructure repositories, so any device on the LAN (or anything that can reach <code>192.168.0.143:3000</code>) can create an account and browse them.</td>
<td>Live <code>/data/gitea/conf/app.ini</code>: <code>DISABLE_REGISTRATION = false</code>, <code>REQUIRE_SIGNIN_VIEW = false</code>; API version 1.27.3; published <code>0.0.0.0:3000</code> and <code>2222:22</code>.</td>
<td><code>DISABLE_REGISTRATION = true</code> (Authentik is the identity provider; keep the OAuth path) and audit per-repository visibility — the secret-gate doctrine in <code>AGENTS.md</code> assumes these repos are not world-readable.</td>
</tr>
<tr>
<td><span class="sev medium">medium</span></td>
<td>Dankclaw (Caddy)</td>
<td><strong>No HSTS anywhere, no CSP on the authenticated vhosts.</strong> The apex redirect drops the one header that pins clients to TLS; the app vhosts differ from each other, so policy is per-vhost accident rather than intent.</td>
<td><code>https://franksdank.cloud</code> → <code>HTTP/2 308, server: Caddy</code> and nothing else. <code>gitea.franksdank.cloud</code> → <code>x-content-type-options: nosniff</code>, <code>x-frame-options: SAMEORIGIN</code>. <code>grafana.franksdank.cloud</code> → bare <code>HTTP/2 200</code>.</td>
<td>Add <code>Strict-Transport-Security: max-age=31536000; includeSubDomains</code> to the Caddy site blocks (and fix the pre-existing <code>max-age=600</code> on the router-side listener), then stage a <code>Content-Security-Policy</code> starting in report-only mode.</td>
</tr>
<tr>
<td><span class="sev medium">medium</span></td>
<td>Dankserver</td>
<td><strong>NFS client helpers exposed on every interface with nothing exported.</strong> <code>rpcbind</code> on <code>0.0.0.0:111</code> plus <code>rpc.statd</code> on <code>0.0.0.0:51651</code>, while <code>/etc/exports</code> contains only comments — attack surface with no consumer.</td>
<td>Root <code>ss -tlnp</code> on both servers; <code>cat /etc/exports</code> → comments only. Dankclaw has the same two listeners.</td>
<td><code>systemctl disable --now rpcbind nfs-common</code> on both Ubuntu boxes (re-enable if an export is ever added).</td>
</tr>
<tr>
<td><span class="sev medium">medium</span></td>
<td>Dankserver, .40/.215</td>
<td><strong>Patch lag and OpenSSH skew.</strong> The Ubuntu boxes are 73 packages behind (6 security) and the two livingroom hosts still run OpenSSH 10.0 while the audited boxes run 10.2/10.6 — three different SSH stacks on one LAN.</td>
<td>Dankserver: <code>apt-get -s upgrade</code> → 73 pending, 6 from <code>*-security*</code>, reboot not required. <code>.40</code>/<code>.215</code>: nmap banner <code>OpenSSH_10.0p1 Ubuntu-2ubuntu12.1</code> on Ubuntu 24.04.4 LTS. blankpad: <code>OpenSSH_10.6p1, OpenSSL 3.6.5</code>; Dankclaw/Dankserver: <code>OpenSSH_10.2p1 Ubuntu-2ubuntu3.8, OpenSSL 3.5.5</code>.</td>
<td>Upgrade the Ubuntu pair in a window (both boxes, same procedure, reboot not required on Dankserver); plan the livingroom hosts into the same key rollout rather than leaving them on an old stack.</td>
</tr>
<tr>
<td><span class="sev medium">medium</span></td>
<td>Dankserver</td>
<td><strong>Host keys predate the installed system and two live addresses are undocumented.</strong> <code>/etc/ssh/ssh_host_*_key</code> are dated 2024-11-29 on a box whose userland is Ubuntu 26.04-era — the keys were carried across a reinstall and never rotated. <code>.247</code> answers alongside <code>.235</code> with the same service set, and the KB names only <code>.235</code>.</td>
<td><code>ls -l --time-style=long-iso /etc/ssh/ssh_*_key</code> → 2024-11-29 (ecdsa/ed25519/rsa, no post-quantum key); ARP: <code>.235 b0:82:e2:a6:39:f3</code>, <code>.247 b0:82:e2:a6:39:f4</code> (same OUI, adjacent NIC) → [INFERENCE] second NIC of the same chassis. blankpad's keys (2026-09-09) already include <code>ssh_host_mldsa44_ed25519_key</code>; Dankclaw's (2026-07-21) and Dankserver's do not.</td>
<td>Rotate Dankserver's host keys after pinning <code>known_hosts</code> on the clients, and record both addresses in <code>omp-docs/system/dankserver.md</code>.</td>
</tr>
<tr>
<td><span class="sev low">low</span></td>
<td>Dankclaw, blankpad</td>
<td><strong>Listeners that no manifest declares.</strong> On Dankclaw a container serves <code>0.0.0.0:8787</code> without a <code>PublishPort=</code> line (host-network), and two <code>PublishPort</code> entries omit the bind address so podman publishes them on all interfaces where their neighbours are explicit.</td>
<td>Root <code>ss -tlnp</code>: <code>0.0.0.0:8787</code> → <code>/opt/hermes/.venv/bin/python /webui/server.py</code> (uid 109999); <code>192.168.0.143:18093</code> → <code>signal-relay.py</code>; <code>192.168.0.143:9401</code> + <code>127.0.0.1:9401</code> → <code>gpu-exporter.py</code>; <code>127.0.0.1:12345</code> → alloy; <code>127.0.0.1:33471</code> → containerd. Manifest grep shows <code>PublishPort=2222:22</code> and <code>PublishPort=3005:8080</code> with no address. blankpad likewise runs <code>python3</code> on <code>0.0.0.0:8899</code> and <code>bun</code> on <code>127.0.0.1:8787</code>.</td>
<td>Write the missing <code>PublishPort=127.0.0.1:…</code> lines so intent is on disk, and adopt the loose host scripts into quadlet/systemd units — every listener should be owned by a unit.</td>
</tr>
<tr>
<td><span class="sev low">low</span></td>
<td>.40/.215</td>
<td><strong>LLMNR enabled on the livingroom hosts</strong> (UDP/TCP 5355) — a legacy name-resolution protocol that answers broadcasts and is routinely poisoned; and their other open ports (<code>8081</code>, <code>27036</code>, <code>32000</code>) have no owner record anywhere.</td>
<td>nmap service probes on <code>.40</code> and <code>.215</code>; identical port sets on both addresses, which are two separate physical boxes (different OUIs: <code>84:47:09:…</code>, <code>4c:23:38:…</code>).</td>
<td><code>LLMRR=no</code> → <code>LLMNR=no</code> in <code>/etc/systemd/resolved.conf</code>; document what runs on those hosts once key access exists.</td>
</tr>
<tr>
<td><span class="sev info">info</span></td>
<td>all 3 boxes</td>
<td><strong>No rootkit or integrity indicators.</strong> NSE <code>rootkit-check</code>, <code>http-malware-host</code>, <code>http-sql-vulnwrapper</code>, <code>http-wordpress-enum</code> and <code>ssl-ccs-injection</code> ran against every reachable web service with no positives; blankpad binaries carry full RELRO, stack canary, Intel CET (SHSTK&amp;IBT), NX and PIE.</td>
<td>nmap NSE results per host; <code>checksec file /usr/bin/sshd</code> → Full RELRO / Canary / CFI SHSTK&amp;IBT / NX / PIE / FORTIFY 7 of 10, same profile for <code>ssh</code>, and <code>sudo</code> 5 of 9 with <code>RUNPATH [/usr/bin/sudo→/usr/lib/sudo]</code>.</td>
<td>Nothing to do; recorded so the next audit has a baseline.</td>
</tr>
</tbody>
</table>
</section>
<section id="hosts">
<h2>Per-host detail</h2>
<h3 id="blankpad">blankpad — dev workstation (192.168.0.140, .104)</h3>
<table>
<thead><tr><th>Field</th><th>Observed</th></tr></thead>
<tbody>
<tr><td>OS / kernel</td><td>CachyOS, <code>7.2.9-1-cachyos</code></td></tr>
<tr><td>SSH</td><td><code>OpenSSH_10.6p1, OpenSSL 3.6.5</code>; unit <code>sshd</code> active + enabled, listening <code>0.0.0.0:22</code> and <code>[::]:22</code></td></tr>
<tr><td>sshd policy</td><td><code>passwordauthentication yes</code> · <code>pubkeyauthentication yes</code> · <code>permitrootlogin prohibit-password</code> · <code>maxauthtries 6</code> · <code>kbdinteractiveauthentication no</code> · <code>usepam yes</code>; ciphers <code>chacha20-poly1305, aes128-gcm, aes256-gcm, aes128-ctr, aes192-ctr, aes256-ctr</code></td></tr>
<tr><td>sshd config files</td><td><code>/etc/ssh/sshd_config.d/20-systemd-userdb.conf</code> (symlink from <code>/usr/lib/systemd</code>), <code>99-archlinux.conf</code> — the drop-ins, not a hand-edited config</td></tr>
<tr><td>Host keys</td><td>2026-09-09: <code>ed25519</code>, <code>ecdsa</code>, <code>rsa</code>, <strong><code>mldsa44_ed25519</code></strong> (post-quantum) — the only box in the fleet offering a PQ host key</td></tr>
<tr><td>Binary hardening</td><td><code>sshd</code>/<code>ssh</code>: Full RELRO, canary, CFI SHSTK&amp;IBT, NX, PIE, no RPATH, FORTIFY 7/10. <code>sudo</code>: same, FORTIFY 5/9, <code>RUNPATH [/usr/lib/sudo]</code></td></tr>
<tr><td>Users with login shells</td><td>none besides <code>root</code> — no stale accounts</td></tr>
<tr><td>TCP listeners (13)</td><td><code>0.0.0.0:22</code> sshd · <code>0.0.0.0:8899</code> python3 · <code>127.0.0.53:53</code> resolved · <code>127.0.0.1:8787</code> bun · <code>127.0.0.1:44179</code> omp · <code>127.0.0.1:6463</code> Discord · <code>127.0.0.1:35507</code> chrome · <code>127.0.0.1:5433</code> passt (rest loopback)</td></tr>
<tr><td>Local tooling</td><td><code>lynis</code> + <code>checksec</code> installed; <code>rkhunter</code>/<code>chkrootkit</code> absent (Arch has no <code>debsecan</code> equivalent — <code>pacman</code> advisories come from the security tracker feed)</td></tr>
</tbody>
</table>
<h3 id="dankclaw">Dankclaw — services box (192.168.0.143)</h3>
<table>
<thead><tr><th>Field</th><th>Observed</th></tr></thead>
<tbody>
<tr><td>SSH</td><td><code>OpenSSH_10.2p1 Ubuntu-2ubuntu3.8, OpenSSL 3.5.5</code>; <code>passwordauthentication yes</code>, <code>permitrootlogin prohibit-password</code>, <code>maxauthtries 6</code>, <code>authenticationmethods any</code>, <code>kbdinteractiveauthentication no</code>; MAC list still offers <code>umac-64-etm</code>, <code>hmac-sha1-etm</code>, <code>umac-64</code>, <code>hmac-sha1</code></td></tr>
<tr><td>Authorised keys</td><td><code>/home/dank/.ssh/authorized_keys</code> 9 entries, <code>/root/.ssh/authorized_keys</code> 3 entries</td></tr>
<tr><td>Host keys</td><td>2026-07-21 (ecdsa, ed25519, rsa)</td></tr>
<tr><td>Containers</td><td>33 quadlet manifests in <code>~/.config/containers/systemd</code>; 15 on <code>:latest</code>, 1 on <code>:main</code>, 1 on <code>:nightly</code> (19 manifest lines / 17 unique references), 4 digest-pinned, 10 exact-tag</td></tr>
<tr><td>Published on all interfaces</td><td><code>0.0.0.0:80</code>, <code>0.0.0.0:443</code> (Caddy) · <code>0.0.0.0:53</code> tcp+udp and <code>0.0.0.0:8083→80</code> (Pi-hole DNS + admin) · <code>0.0.0.0:3000</code>, <code>2222:22</code> (Gitea) · <code>0.0.0.0:8188</code>, <code>0.0.0.0:8502</code>, <code>3005:8080</code> · <code>389→3389</code>, <code>636→6636</code> (Authentik LDAP/LDAPS) · <code>7772:7772</code> (embedding proxy) · <code>8081:8080</code>, <code>8082:8085</code>, <code>9119:9119</code> · <code>0.0.0.0:8787</code> (unmanifested, see findings)</td></tr>
<tr><td>Published loopback-only</td><td><code>127.0.0.1:3002</code> Grafana · <code>127.0.0.1:3100</code> Loki · <code>127.0.0.1:9090</code> Prometheus · <code>127.0.0.1:9093</code> Alertmanager · <code>127.0.0.1:9000</code> Authentik · <code>127.0.0.1:5055</code>, <code>127.0.0.1:5056→5055</code>, <code>127.0.0.1:8080</code> + <code>192.168.0.143:8080</code></td></tr>
<tr><td>Grafana</td><td>13.2.2 commit <code>1bea008f7e4e858b6824c9e364d608bd4d10b13a</code> via <code>/api/health</code>; live <code>/etc/grafana/grafana.ini</code> has <code>;enabled = false</code> under <code>[auth.anonymous]</code> — anonymous access is <strong>off</strong>; env file mode <code>600</code>, contains only <code>GRAFANA_OAUTH_CLIENT_SECRET</code></td></tr>
<tr><td>Caddy</td><td><code>franksdank/caddy-porkbun:latest</code>; Caddyfile fronts both hosts, guarded vhosts route through Anubis → Authentik, apps with their own auth exempt by construction</td></tr>
<tr><td>Pi-hole</td><td><code>pihole/pihole:latest</code>; env <code>ServerIP=192.168.0.143</code>, <code>DNS1=1.1.1.1</code>, <code>DNS2=1.0.0.1</code>, <code>WEBPASSWORD=&lt;set&gt;</code> — the admin UI is on <code>0.0.0.0:8083</code> rather than behind Caddy</td></tr>
<tr><td>Host processes</td><td><code>signal-relay.py</code> (18093), <code>gpu-exporter.py --serve</code> (9401), <code>alloy</code> (12345), <code>containerd</code> devv socket (33471) — scripts from <code>~/serverAppConfigs/scripts</code>, not declared as quadlets</td></tr>
</tbody>
</table>
<h3 id="dankserver">Dankserver — main model box (192.168.0.235, .247)</h3>
<table>
<thead><tr><th>Field</th><th>Observed</th></tr></thead>
<tbody>
<tr><td>SSH</td><td><code>OpenSSH_10.2p1 Ubuntu-2ubuntu3.8, OpenSSL 3.5.5</code>; <code>passwordauthentication yes</code>, <code>permitrootlogin prohibit-password</code>, <code>maxauthtries 6</code>, <code>usepam yes</code></td></tr>
<tr><td>Authorised keys</td><td><code>/home/dank/.ssh/authorized_keys</code> 7 entries; <code>/root/.ssh/authorized_keys</code> not readable by <code>dank</code> (unprivileged <code>cat</code> → permission denied)</td></tr>
<tr><td>Host keys</td><td>2024-11-29 — predates the current Ubuntu userland; no post-quantum host key</td></tr>
<tr><td>Packages</td><td>73 upgradable, 6 from <code>*-security</code>; reboot not required</td></tr>
<tr><td>Containers</td><td>12 quadlet manifests; 4 on <code>:latest</code> (<code>prom/node-exporter</code>, <code>9001/copyparty-ac</code>, <code>jellyfin/jellyfin</code> → 12.1.0 live, <code>rommapp/romm</code>); the rest pinned, including <code>linuxserver/plex:1.43.5.11029-6bf8af3f0-ls329</code> and <code>linuxserver/calibre-web:0.6.27-ls402</code></td></tr>
<tr><td>Host services</td><td><code>radiance</code> inference on <code>*:7770</code> (native process, not a container), <code>syncthing</code> <code>*:8384</code> (user unit enabled), <code>gnome-remote-de</code> RDP on <code>*:3389</code> (user unit active, system unit disabled), <code>rpcbind</code> <code>0.0.0.0:111</code>, <code>rpc.statd</code> <code>0.0.0.0:51651</code></td></tr>
<tr><td>NFS</td><td><code>/etc/exports</code> contains comments only — nothing exported, so the two NFS helper daemons serve nothing</td></tr>
<tr><td>Second address</td><td><code>.247</code> (ARP <code>b0:82:e2:a6:39:f4</code>) presents the same service set as <code>.235</code> (<code>b0:82:e2:a6:39:f3</code>) — [INFERENCE] second NIC of the same chassis; undocumented in the KB</td></tr>
</tbody>
</table>
<h3 id="observed">Observed without credentials</h3>
<table>
<thead><tr><th>Address</th><th>Identity</th><th>Evidence</th><th>Action</th></tr></thead>
<tbody>
<tr><td><code>.40</code> and <code>.215</code></td><td>danklivingroom — two distinct boxes (OUIs <code>84:47:09</code>, <code>4c:23:38</code>) with identical port profiles</td><td>SSH auth probe returns <code>Ubuntu 24.04.4 LTS</code> + <code>Permission denied (publickey,password)</code>; nmap banner <code>OpenSSH_10.0p1 Ubuntu-2ubuntu12.1</code>; open ports <code>22, 5355, 8081, 27036, 32000</code> on both</td><td>Install the fleet key (no password auth needed), then patch and document; see the LLMNR finding</td></tr>
<tr><td><code>.75</code></td><td>Apple device</td><td>Open ports <code>853, 49152, 62078, 62742, 62805</code> — <code>62078</code> is the Apple mobile-sync service; mDNS name present</td><td>Managed handset/tablet: nothing to patch from here; record it in the network page so it stops showing up as an unknown</td></tr>
<tr><td><code>.112</code></td><td>dankstation</td><td>Seen by the earlier discovery pass (mDNS + SSH, 7 ports via nmap); <strong>absent</strong> from the 2026-10-21 fping/masscan sweep</td><td>Confirm whether it is asleep or was renamed — the KB has no current entry</td></tr>
<tr><td><code>.1</code></td><td>ARRIS gateway (ISP router, Wi-Fi password holder)</td><td>Open ports <code>80, 111, 443, 8181, 49152, 50011, 50012, 51515</code>; HTTP banner <code>server: ARRIS</code>; auth probe reports password auth (no key accepted)</td><td>Admin UI is LAN-reachable; change the default credential and disable HTTP if the vendor build allows</td></tr>
</tbody>
</table>
</section>
<section id="network">
<h2>LAN exposure map</h2>
<figure>
<svg viewBox="0 0 1000 470" role="img" aria-label="Fleet attack surface" style="width:100%;height:auto;color:#1e293b">
<defs>
<marker id="a" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 z" fill="var(--secondary)"/></marker>
</defs>
<rect x="0" y="0" width="1000" height="470" fill="none"/>
<!-- internet -->
<g>
<rect x="20" y="30" width="150" height="56" rx="10" fill="none" stroke="var(--secondary)" stroke-width="1.5"/>
<text x="95" y="54" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">Internet</text>
<text x="95" y="72" text-anchor="middle" font-size="11" fill="var(--secondary)">WAN</text>
</g>
<!-- router -->
<g>
<rect x="20" y="140" width="150" height="86" rx="10" fill="none" stroke="var(--warning)" stroke-width="1.5"/>
<text x="95" y="164" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">.1 ARRIS</text>
<text x="95" y="182" text-anchor="middle" font-size="11" fill="var(--secondary)">80 · 443 · 8181</text>
<text x="95" y="198" text-anchor="middle" font-size="11" fill="var(--secondary)">111 · 49152</text>
<text x="95" y="214" text-anchor="middle" font-size="11" fill="var(--danger)">admin UI on LAN</text>
</g>
<line x1="95" y1="86" x2="95" y2="138" stroke="var(--secondary)" stroke-width="1.5" marker-end="url(#a)"/>
<!-- lan bus -->
<g>
<rect x="20" y="380" width="960" height="60" rx="10" fill="none" stroke="var(--primary)" stroke-width="1.5"/>
<text x="500" y="405" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">LAN 192.168.0.0/24 — 27 live hosts (fping), 78 open TCP ports (masscan, 1–65535)</text>
<text x="500" y="424" text-anchor="middle" font-size="11" fill="var(--secondary)">named: .1 router · .104/.140 blankpad · .143 Dankclaw · .235/.247 Dankserver · .40/.215 danklivingroom · .75 Apple · .112 dankstation (absent 2026-10-21)</text>
</g>
<line x1="95" y1="226" x2="95" y2="378" stroke="var(--secondary)" stroke-width="1.5" marker-end="url(#a)"/>
<!-- blankpad -->
<g>
<rect x="200" y="30" width="230" height="110" rx="10" fill="none" stroke="var(--secondary)" stroke-width="1.5"/>
<text x="315" y="54" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">blankpad</text>
<text x="315" y="72" text-anchor="middle" font-size="11" fill="var(--secondary)">CachyOS · OpenSSH 10.6p1</text>
<text x="315" y="90" text-anchor="middle" font-size="11" fill="var(--danger)">0.0.0.0:22 sshd · 0.0.0.0:8899 python3</text>
<text x="315" y="108" text-anchor="middle" font-size="11" fill="var(--secondary)">10 other listeners, loopback only</text>
<text x="315" y="126" text-anchor="middle" font-size="11" fill="var(--success)">PQ host key (mldsa44) · CET on sshd/sudo</text>
</g>
<!-- dankclaw -->
<g>
<rect x="460" y="30" width="250" height="130" rx="10" fill="none" stroke="var(--danger)" stroke-width="1.5"/>
<text x="585" y="54" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">Dankclaw</text>
<text x="585" y="72" text-anchor="middle" font-size="11" fill="var(--secondary)">Ubuntu 26.04 · 33 quadlets</text>
<text x="585" y="90" text-anchor="middle" font-size="11" fill="var(--danger)">10 published on 0.0.0.0</text>
<text x="585" y="108" text-anchor="middle" font-size="11" fill="var(--secondary)">80 443 53 8083 3000 8188 8502 3005 7772 8787</text>
<text x="585" y="126" text-anchor="middle" font-size="11" fill="var(--warning)">17 images on :latest</text>
<text x="585" y="144" text-anchor="middle" font-size="11" fill="var(--secondary)">Caddy → Anubis → Authentik</text>
</g>
<!-- dankserver -->
<g>
<rect x="740" y="30" width="240" height="130" rx="10" fill="none" stroke="var(--warning)" stroke-width="1.5"/>
<text x="860" y="54" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">Dankserver</text>
<text x="860" y="72" text-anchor="middle" font-size="11" fill="var(--secondary)">Ubuntu 26.04 · 12 quadlets</text>
<text x="860" y="90" text-anchor="middle" font-size="11" fill="var(--danger)">73 pkgs behind (6 security)</text>
<text x="860" y="108" text-anchor="middle" font-size="11" fill="var(--secondary)">radiance :7770 · 4 images :latest</text>
<text x="860" y="126" text-anchor="middle" font-size="11" fill="var(--warning)">rpcbind :111 + rpc.statd, no exports</text>
<text x="860" y="144" text-anchor="middle" font-size="11" fill="var(--secondary)">host keys 2024-11-29</text>
</g>
<!-- livingroom -->
<g>
<rect x="460" y="190" width="250" height="110" rx="10" fill="none" stroke="var(--secondary)" stroke-width="1.5" stroke-dasharray="5 4"/>
<text x="585" y="214" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">danklivingroom</text>
<text x="585" y="232" text-anchor="middle" font-size="11" fill="var(--secondary)">.40 + .215 · Ubuntu 24.04.4</text>
<text x="585" y="250" text-anchor="middle" font-size="11" fill="var(--danger)">OpenSSH 10.0p1 · key auth refused</text>
<text x="585" y="268" text-anchor="middle" font-size="11" fill="var(--secondary)">22 5355 8081 27036 32000</text>
<text x="585" y="286" text-anchor="middle" font-size="11" fill="var(--warning)">LLMNR enabled</text>
</g>
<!-- apple -->
<g>
<rect x="740" y="190" width="240" height="94" rx="10" fill="none" stroke="var(--secondary)" stroke-width="1.5" stroke-dasharray="5 4"/>
<text x="860" y="214" text-anchor="middle" font-size="14" font-weight="600" fill="currentColor">.75 Apple device</text>
<text x="860" y="232" text-anchor="middle" font-size="11" fill="var(--secondary)">853 49152 62078 62742 62805</text>
<text x="860" y="250" text-anchor="middle" font-size="11" fill="var(--secondary)">mobile-sync exposed on Wi-Fi</text>
<text x="860" y="268" text-anchor="middle" font-size="11" fill="var(--secondary)">managed endpoint, out of band</text>
</g>
<line x1="315" y1="140" x2="315" y2="378" stroke="var(--secondary)" stroke-width="1.2" marker-end="url(#a)"/>
<line x1="585" y1="160" x2="585" y2="378" stroke="var(--secondary)" stroke-width="1.2" marker-end="url(#a)"/>
<line x1="860" y1="160" x2="860" y2="378" stroke="var(--secondary)" stroke-width="1.2" marker-end="url(#a)"/>
<line x1="585" y1="300" x2="585" y2="378" stroke="var(--secondary)" stroke-width="1.2" stroke-dasharray="5 4" marker-end="url(#a)"/>
<line x1="860" y1="284" x2="860" y2="378" stroke="var(--secondary)" stroke-width="1.2" stroke-dasharray="5 4" marker-end="url(#a)"/>
<text x="200" y="176" font-size="11" fill="var(--secondary)">solid = audited with credentials · dashed = observed via scan only</text>
</svg>
<figcaption>Audited hosts and every port each one answers on, 2026-10-21.</figcaption>
</figure>
</section>
<section id="images">
<h2>Image census — the pinning table</h2>
<p>The same repo writes both styles on the same host. <span class="tag mutable">mutable</span> means a
restart can change the running binary; <span class="tag pin">pinned</span> means the manifest states what
is running. Verified versions were read from the live services, not the tags.</p>
<h3>Dankclaw — 33 manifests, 17 on <code>:latest</code></h3>
<table>
<thead><tr><th>Image</th><th>Status</th><th>Live version</th></tr></thead>
<tbody>
<tr><td><code>docker.io/gitea/gitea:latest</code></td><td><span class="tag mutable">mutable</span></td><td>1.27.3 (API)</td></tr>
<tr><td><code>docker.io/grafana/grafana:latest</code></td><td><span class="tag mutable">mutable</span></td><td>13.2.2 / <code>1bea008f7e4e858b6824c9e364d608bd4d10b13a</code></td></tr>
<tr><td><code>franksdank/caddy-porkbun:latest</code></td><td><span class="tag mutable">mutable</span></td><td>serves 80/443, <code>server: Caddy</code></td></tr>
<tr><td><code>docker.io/pihole/pihole:latest</code></td><td><span class="tag mutable">mutable</span></td><td>DNS 53 + admin 8083</td></tr>
<tr><td><code>docker.io/prom/prometheus:latest</code>, <code>prom/alertmanager:latest</code>, <code>prom/node-exporter:latest</code></td><td><span class="tag mutable">mutable</span></td><td>loopback-published</td></tr>
<tr><td><code>ghcr.io/searxng/searxng:latest</code>, <code>ghcr.io/manualdousuario/marreta:latest</code>, <code>ghcr.io/open-webui/open-webui:main</code>, <code>docker.io/qmcgaw/gluetun:latest</code>, <code>docker.io/binwiederhier/ntfy:latest</code></td><td><span class="tag mutable">mutable</span></td><td>—</td></tr>
<tr><td><code>localhost/franksdank/frank-tts:latest</code>, <code>frank-tts-engine:latest</code>, <code>localhost/hermes-agent:latest</code> (×3)</td><td><span class="tag mutable">mutable</span></td><td>hermes webui answers on <code>0.0.0.0:8787</code></td></tr>
<tr><td><code>docker.io/lightpanda/browser:nightly</code></td><td><span class="tag mutable">mutable</span></td><td>—</td></tr>
<tr><td><code>ghcr.io/goauthentik/server:2026.8.3</code> (×3), <code>ghcr.io/manualdousuario/marreta</code>, <code>ghcr.io/seerr-team/seerr:v3.4.1</code>, <code>techarohq/anubis:v1.27.0</code>, <code>gcr.io/cadvisor/cadvisor:v0.49.1</code>, <code>docker.io/library/postgres:16-alpine</code> (×2), <code>docker.io/valkey/valkey:9-alpine</code>, <code>localhost/comfyui-rocm:gfx1151</code></td><td><span class="tag pin">pinned</span></td><td>—</td></tr>
<tr><td><code>lfnovo/open_notebook:v1-latest@sha256:54b2025a…</code>, <code>surrealdb/surrealdb:v2@sha256:e5d7387e…</code>, <code>chromedp/headless-shell@sha256:2d349b54…</code>, <code>ghcr.io/goauthentik/ldap@sha256:2e7b259e…</code></td><td><span class="tag pin">digest-pinned</span></td><td>the pattern every manifest should follow</td></tr>
</tbody>
</table>
<h3>Dankserver — 12 manifests, 4 on <code>:latest</code></h3>
<table>
<thead><tr><th>Image</th><th>Status</th><th>Live version</th></tr></thead>
<tbody>
<tr><td><code>ghcr.io/jellyfin/jellyfin:latest</code></td><td><span class="tag mutable">mutable</span></td><td>12.1.0 (<code>/System/Info/Public</code>)</td></tr>
<tr><td><code>ghcr.io/rommapp/romm:latest</code>, <code>ghcr.io/9001/copyparty-ac:latest</code>, <code>docker.io/prom/node-exporter:latest</code></td><td><span class="tag mutable">mutable</span></td><td>—</td></tr>
<tr><td><code>localhost/radiance-vllm:0.13.0-e060895</code>, <code>lscr.io/linuxserver/plex:1.43.5.11029-6bf8af3f0-ls329</code>, <code>linuxserver/calibre:9.15.0</code>, <code>linuxserver/calibre-web:0.6.27-ls402</code>, <code>linuxserver/tautulli:v2.18.1-ls245</code>, <code>docker.io/library/mariadb:11</code>, <code>redis:7-alpine</code>, <code>gcr.io/cadvisor/cadvisor:v0.49.1</code></td><td><span class="tag pin">pinned</span></td><td>—</td></tr>
</tbody>
</table>
<div class="note"><strong>Why this matters more than the tag itself:</strong> an unpinned service cannot be
tied to an advisory. Half of Dankclaw's stack is pinned by someone's habit and half is not, so a
<code>git diff</code> no longer tells you what code is running — the assumption the whole
"the checkout is the deployment" doctrine rests on.</div>
</section>
<section id="cve">
<h2>Advisory cross-reference</h2>
<p>Versions come from live sources only — OSV <code>POST /v1/query</code> in the correct ecosystem
(<code>Ubuntu</code>/<code>Alpine</code> for distro packages, <code>Go</code>/<code>PyPI</code>/<code>crates.io</code>
for application code), the Ubuntu Security Tracker, the Alpine secdb, GitHub repository advisories, and
<code>podman exec … --version</code> inside each container. The complete per-host tables live beside this
report: <a href="vuln-dankclaw.md">vuln-dankclaw.md</a> (33 Dankclaw images + host) and
<a href="vuln-dankserver.md">vuln-dankserver.md</a> (Dankserver, blankpad, danklivingroom). The tables below
are the cross-host summary; <span class="tag">re-verified</span> marks a version this session re-probed
directly from blankpad on 2026-10-21.</p>
<h3>Ubuntu hosts — Dankclaw and Dankserver</h3>
<table>
<thead><tr><th>Component</th><th>Installed</th><th>Severity</th><th>Advisory / fix</th></tr></thead>
<tbody>
<tr><td><code>openssh</code> (source package), both servers</td><td><code>1:10.2p1-2ubuntu3.8</code> <span class="tag">re-verified</span></td><td><span class="sev medium">medium</span></td><td><a href="https://ubuntu.com/security/CVE-2026-110923">CVE-2026-110923</a> plus CVE-2026-110924, -110925, -110926, -110927 — <strong>5 unpatched, no Ubuntu fix released</strong> (<code>apt-cache policy</code>: candidate == installed; tracker status <code>needs-triage</code>, CVSS 5.5–6.5). An earlier pass recorded "0 open advisories" here: the OSV purl-only query shape returns nothing for that build, the <code>name</code>+<code>ecosystem</code>+<code>version</code> form returns the five.</td></tr>
<tr><td><code>gnome-remote-desktop</code> (Dankserver)</td><td><code>50.2-0ubuntu0.1</code></td><td><span class="sev medium">medium</span></td><td>5 CVEs (CVE-2025-5024, CVE-2026-109832, CVE-2026-109833, CVE-2026-18358, CVE-2026-96541), none fixed for 26.04 — the RDP listener sits on <code>*:3389</code></td></tr>
<tr><td><code>rpcbind</code> (Dankserver)</td><td><code>1.2.7-1build2</code></td><td><span class="sev medium">medium</span></td><td>3 CVEs (CVE-2026-16277, CVE-2026-16461, CVE-2026-94640), none fixed for 26.04; the daemon serves nothing (<a href="#hosts">NFS exports are empty</a>) yet answers on <code>0.0.0.0:111</code></td></tr>
<tr><td><code>openssl</code>/<code>libssl3t64</code>, <code>nfs-utils</code>, <code>samba</code>, <code>syncthing</code></td><td>3.5.5-1ubuntu3.7, 1:2.8.5-1ubuntu1, 2:4.23.6+dfsg-1ubuntu2.2, 1.29.5~ds1-3</td><td><span class="sev info">clean</span></td><td>OSV <code>Ubuntu</code> returns no applicable advisory at the installed versions (<code>syncthing</code>: 3 records, all patched before 1.29.5)</td></tr>
<tr><td>kernel (Dankserver)</td><td><code>7.0.0-38.38</code></td><td><span class="sev info">untriaged</span></td><td>35 OSV records list the installed kernel as affected with no <code>fixed</code> event — <code>needs-triage</code>, not confirmed vulnerable</td></tr>
</tbody>
</table>
<h3>Dankclaw containers <span class="tag">re-verified</span></h3>
<table>
<thead><tr><th>Container / image</th><th>Running version</th><th>Severity</th><th>Advisory / fix</th></tr></thead>
<tbody>
<tr><td><code>open-notebook-surrealdb</code><br><code>surrealdb/surrealdb:v2@sha256:e5d7387…</code></td><td>2.7.0 (<code>/surreal version</code>)</td><td><span class="sev high">high</span></td><td>25 advisories, 6 HIGH (<a href="https://github.com/surrealdb/surrealdb/security/advisories/GHSA-848m-r628-vrxw">CVE-2026-63735</a>, GHSA-4vgr-h27g-cf9p, GHSA-5qfp-32cf-69jh, GHSA-cc8f-fcx3-gpjr, CVE-2026-63760, GHSA-wjjj-24cx-f28g). <strong>Every fix is on the 3.x line</strong> — the pinned v2 tag is end-of-line, so this is a major-version migration, not a rebuild.</td></tr>
<tr><td><code>gitea-server</code><br><code>gitea/gitea:latest</code></td><td>1.27.3 (<code>/api/v1/version</code>)</td><td><span class="sev info">patched</span></td><td><a href="https://github.com/go-gitea/gitea/security/advisories/GHSA-rcr6-4jqh-j84m">CVE-2026-60004</a> (CRITICAL, RCE through the diffpatch git hook) and GHSA-cm61-xmth-gqwh (cacheable session) were both fixed in 1.27.1 — the running image carries the fix. The exposure here is F3 (open registration + public read), not the build.</td></tr>
<tr><td><code>pihole</code><br><code>pihole/pihole:latest</code></td><td>Core v6.4.3 · Web v6.6 · FTL v6.7.1 (<code>pihole -v</code>)</td><td><span class="sev high">high</span></td><td>12 FTL + 3 web advisories published on/after the image build (2026-09-19), incl. GHSA-2h7g-g549-hf74 (authenticated file read + fix bypass), GHSA-2794-hrj8-5jg9 (<code>webserver.advancedOpts</code> RCE → root), GHSA-ww5x-xx4x-qvjr (<code>misc.dnsmasq_lines</code> RCE); vendor is at FTL v6.8 / Core v6.5 / Web v6.6.1. Its Alpine shell measures <code>musl 1.2.5-r2</code> + <code>libssl3 3.5.6-r0</code> → <a href="https://secdb.alpinelinux.org/v3.24/main.json">CVE-2026-36448 (CVSS 9.8)</a>, CVE-2026-31974, CVE-2026-39171.</td></tr>
<tr><td><code>searxng-valkey</code><br><code>valkey/valkey:9-alpine@sha256:31e788e7…</code></td><td>9.1.2 (<code>valkey-server --version</code>)</td><td><span class="sev high">high</span></td><td>4 vendor advisories — <a href="https://github.com/valkey-io/valkey/security/advisories/GHSA-mvcj-73cw-22m4">CVE-2026-63639</a>, CVE-2026-56684, GHSA-jcj7-v34w-v9vv, GHSA-fq2f-crmw-q97r — applicability unconfirmed (the Alpine secdb stops at <code>9.0.4-r0</code>; the image is a from-source build). Reachable only from the searxng pod network.</td></tr>
<tr><td><code>gitea-postgres</code>, <code>authentik-postgres</code><br><code>postgres:16-alpine@sha256:06f9702…</code></td><td>16.15 (<code>postgres --version</code>)</td><td><span class="sev info">unverifiable</span></td><td>PostgreSQL server CVEs are published on postgresql.org and are not in OSV/GHSA; <code>postgresql16</code> is absent from the Alpine secdb (from-source build), so no tracker in the query set covers 16.15.</td></tr>
<tr><td><code>caddy</code><br><code>franksdank/caddy-porkbun:latest</code></td><td>v2.11.7 (<code>caddy version</code>) → <code>docker.io/library/caddy:v2.11.7_alpine@sha256:684242074367…</code></td><td><span class="sev info">clean</span></td><td>No OSV record for <code>github.com/caddyserver/caddy@2.11.7</code>. The mutable local tag hides the upstream pin (F2) — record the digest in the manifest.</td></tr>
<tr><td>Alpine 3.24 shells — <code>gitea-server</code>, <code>grafana</code>, <code>ntfy</code>, <code>authentik-postgres</code>, <code>frank-tts</code></td><td><code>musl 1.2.6-r2</code>, <code>libssl3 3.5.7-r0</code></td><td><span class="sev medium">medium</span></td><td><a href="https://secdb.alpinelinux.org/v3.24/main.json">musl → CVE-2026-107891 (fixed <code>1.2.6-r3</code>)</a>; libssl3 → 10 CVEs fixed at <code>3.5.8-r0</code>. Shells on 3.23 (gluetun, caddy, seerr) were not fetched — backport status unknown.</td></tr>
</tbody>
</table>
<h3>Dankserver containers <span class="tag">re-verified</span></h3>
<table>
<thead><tr><th>Container / image</th><th>Running version</th><th>Severity</th><th>Advisory / fix</th></tr></thead>
<tbody>
<tr><td><code>plex</code><br><code>lscr.io/linuxserver/plex:1.43.5.11029-6bf8af3f0-ls329</code></td><td>1.43.5.11029 (<code>cat /build_version</code>, build-date 2026-10-20)</td><td><span class="sev high">high</span></td><td>Plex publishes no CVE feed and has no OSV ecosystem; upstream is at <strong>1.43.6.11150</strong>, a security release, so the pin is one minor behind. The earlier pass attributed "12.1.0" to Plex — that string is Jellyfin's version (see the note at the end of this section).</td></tr>
<tr><td><code>copyparty</code><br><code>ghcr.io/9001/copyparty:v1.26.2</code> (image <code>2284b21e4259</code>)</td><td>1.20.24 (image label)</td><td><span class="sev medium">medium</span></td><td><a href="https://github.com/9001/copyparty/security/advisories/GHSA-3c88-p299-7hvr">GHSA-3c88-p299-7hvr</a> (fixed 1.20.25) and GHSA-hg99-jqfp-rf76 (low, fixed 1.20.26) are both newer than the running build — the tag moved without the container being rebuilt.</td></tr>
<tr><td><code>redis</code><br><code>docker.io/library/redis:7-alpine@sha256:2ed3d0c…</code></td><td>v=7.4.11 (<code>redis-server --version</code>)</td><td><span class="sev high">high</span></td><td>12 vendor advisories (<a href="https://github.com/redis/redis/security/advisories/GHSA-93m2-935m-8rj3">CVE-2026-23479</a>, CVE-2026-25243, CVE-2025-46817, CVE-2025-48367, CVE-2025-32023, CVE-2025-21605 …) carry <code>patched: TBD</code> upstream — no fixed 7.4.x release exists to move to. CVE-2025-49844 is fixed at 7.4.6, so it does not apply.</td></tr>
<tr><td><code>romm-mariadb</code><br><code>docker.io/library/mariadb:11@sha256:943995c7…</code></td><td>11.8.9 (<code>mariadb --version</code>)</td><td><span class="sev info">unverifiable</span></td><td>Upstream MariaDB has no OSV ecosystem; the 310 name-only records belong to Debian/Ubuntu/Alpine builds and cannot be attributed to this image. The 4 security fixes released for the 11.8.6 line were recorded against a "11.8.5" reading in the earlier pass — the installed build is 11.8.9.</td></tr>
<tr><td><code>romm</code><br><code>ghcr.io/rommapp/romm@sha256:eab97d88d9d7…</code></td><td>5.3.1 (<code>cat /backend/__version__.py</code>)</td><td><span class="sev info">clean</span></td><td>None of the 15 repository advisories applies (all patched earlier), but upstream is at 5.9.0 — 12 releases behind, which is where future exposure comes from.</td></tr>
<tr><td><code>jellyfin</code><br><code>ghcr.io/jellyfin/jellyfin@sha256:6370ab0005b4…</code></td><td>12.1.0 (<code>/System/Info/Public</code>)</td><td><span class="sev info">clean</span></td><td>None of the published repository advisories applies at 12.1.0 — all patched ranges end at ≤ 12.0, including the earlier pass's GHSA-vrc3-37vx-82q5 / CVE-2026-44208 row. The three newest advisories (GHSA-cf3c-8m59-2vhx SVG SSRF, GHSA-6828-c7cx-hvqm virtual-folder traversal, GHSA-4vx8-xhc9-qg6x session control) fix later releases.</td></tr>
<tr><td><code>calibre-web</code> / <code>calibre</code></td><td>0.6.27-ls402 / 9.15.0 (image tags)</td><td><span class="sev info">unverifiable</span></td><td>No OSV record in the PyPI ecosystem at calibre-web 0.6.27 and none for calibre 9.15.0; the earlier pass's CVE-2026-42811 (fixed 0.6.28) came from the Ubuntu tracker for a different build line.</td></tr>
<tr><td><code>tautulli</code><br><code>lscr.io/linuxserver/tautulli:v2.18.1-ls245</code></td><td>2.18.1 (tag)</td><td><span class="sev info">clean</span></td><td>18 repository advisories, all patched ≤ 2.17.2</td></tr>
<tr><td><code>cadvisor</code> / <code>cadvisor-test</code></td><td>v0.49.1 (images built 2024-03-02, Alpine 3.19 / 3.18.6 bases)</td><td><span class="sev medium">medium</span></td><td>No application advisory; the exposure is the base image — 63 GHSA on the Alpine 3.19 shell (61 fix-available), and v0.49.1 is 2.5 years old.</td></tr>
<tr><td><code>frank-archon</code> (native radiance, image <code>localhost/radiance-vllm:0.13.0-e060895</code>)</td><td>0.13.0 — tag-derived only: the running container is <code>docker.io/stilldeadcode/radiance@sha256:d590e300…</code> and ships no <code>python3</code> to confirm the embedded vLLM</td><td><span class="sev critical">critical</span></td><td>Assessed against vLLM 0.13.0: <a href="https://github.com/vllm-project/vllm/security/advisories/GHSA-4r2x-xpjr-7cvv">GHSA-4r2x-xpjr-7cvv</a> and GHSA-94f4-hr76-p5j6 (CRITICAL, fixed 0.14.1 / 0.22.0) plus 48 more. If the fork carries a different vLLM base the whole row set changes — flagged unverifiable in the working page.</td></tr>
</tbody>
</table>
<h3>Observed without credentials</h3>
<table>
<thead><tr><th>Host</th><th>Component</th><th>Severity</th><th>Advisory / fix</th></tr></thead>
<tbody>
<tr><td>danklivingroom <code>.40</code> / <code>.215</code></td><td>OpenSSH <code>10.0p1</code> — banner verified by probe; OS reported <code>Ubuntu 24.04.4 LTS</code>, package version <code>1:10.0p1-2ubuntu12.1</code></td><td><span class="sev medium">medium</span></td><td>8 CVEs fixed for the 10.0p1 source line (CVE-2025-61984, CVE-2025-61985, CVE-2026-3497, CVE-2026-35385, -35386, -35387, -35388, -35414 — <a href="https://ubuntu.com/security/CVE-2026-35385">USN-8222-1</a>, USN-8090-1). Nothing else on the box is assessable: key auth refused, so no inventory (<a href="#caveats">caveat</a>).</td></tr>
<tr><td>blankpad (Arch)</td><td>1,359 installed packages</td><td><span class="sev info">clean</span></td><td>0 packages match an Arch advisory with a newer fix version (2,446-advisory feed matched on <code>pkgbase</code>, control-tested against deliberately old versions so the matcher is not vacuous). Two advisories stay open upstream without a fixed version: AVG-2882 (openssl CVE-2025-4575, low), AVG-2893 (systemd CVE-2025-4598, medium). The <code>linux-cachyos</code> kernel is not in the tracker at all.</td></tr>
</tbody>
</table>
<div class="note"><strong>Working-file reconciliation.</strong> Three claims in the in-progress pass were corrected while folding the per-host pages into this report: (1) <strong>OpenSSH on Ubuntu</strong> — "0 open advisories" came from an OSV query shape that returns nothing for that purl; the corrected query and the Ubuntu tracker both report five unpatched CVEs. (2) <strong>Plex "12.1.0"</strong> — that version belongs to Jellyfin; the live Plex build is <code>1.43.5.11029-6bf8af3f0-ls329</code>. (3) <strong>Dankserver mariadb "11.8.5"</strong> — the running container reports 11.8.9. The Dankclaw mutable-tag census also differs by definition (19 manifests here, 24 in the working page, which counts rolling release tags as mutable); both counts are shown in <a href="#findings">F2</a>.</div>
</section>
<section id="fixes">
<h2>Remediation</h2>
<h3>P0 — this week, one change set</h3>
<pre><code># 1. rotate the fleet password once, then close the door on all three boxes
# (verify keys in a second session first)
printf 'PasswordAuthentication no\n' | sudo tee /etc/ssh/sshd_config.d/99-audit.conf
sudo sshd -t &amp;&amp; sudo systemctl reload sshd
# 2. stop echoing the secret in every command line
# servers already allow `sudo -n` for systemctl; blankpad keeps its sudoers entry
# 3. Gitea: stop self-registration, keep the Authentik path
DISABLE_REGISTRATION = true # /data/gitea/conf/app.ini</code></pre>
<h3>P1 — next change set</h3>
<ul>
<li>Pin all 21 mutable images to <code>tag@sha256:digest</code> in the quadlet manifests, one commit per host; the repo already digest-pins four images, so this is finishing an existing pattern, not inventing one.</li>
<li>Caddy: <code>Strict-Transport-Security: max-age=31536000; includeSubDomains</code> on every TLS site (the router-side listener currently sends <code>max-age=600</code>), then CSP in report-only.</li>
<li>Bind <code>PublishPort=2222:22</code> and <code>3005:8080</code> explicitly (<code>127.0.0.1:</code>) and give <code>0.0.0.0:8787</code> (hermes webui) a manifest line so the socket matches the repo.</li>
</ul>
<h3>P2 — with the next maintenance window</h3>
<ul>
<li><code>apt-get upgrade</code> on Dankserver (73 packages, 6 security, no reboot flag) and the equivalent on Dankclaw.</li>
<li><code>systemctl disable --now rpcbind nfs-common</code> on both Ubuntu boxes — nothing is exported.</li>
<li>Rotate Dankserver's SSH host keys (dated 2024-11-29) after pinning them in client <code>known_hosts</code>; consider shipping a post-quantum host key there and on Dankclaw the way blankpad already does.</li>
<li>danklivingroom: install the fleet key on <code>.40</code>/<code>.215</code>, patch OpenSSH 10.0, set <code>LLMNR=no</code>.</li>
</ul>
</section>
<section id="caveats">
<h2>Caveats and refutations</h2>
<ul>
<li><strong>Refuted — Grafana anonymous access.</strong> Carried forward as a finding by an earlier
survey (<code>[auth.anonymous] enabled=true, org_role=1</code>). The live container config reads
<code>;enabled = false</code> — a commented default, i.e. anonymous access is off. The earlier claim
came from a checkout path on the dev box, not from Dankclaw.</li>
<li><strong>Refuted — "Grafana bound to <code>127.0.0.1:3000</code>".</strong> The manifest publishes
<code>127.0.0.1:3002:3000</code>; port 3000 on that host belongs to Gitea.</li>
<li><strong>Refuted — "Pi-hole / SearXNG / Open WebUI quadlets missing".</strong> All three exist in
<code>~/.config/containers/systemd</code>; the survey had read a stale worktree path.</li>
<li><strong>Not verifiable this pass:</strong> configuration state of <code>.40</code>/<code>.215</code>
(key auth refused), <code>.75</code> and the router — banner and port evidence only; whether
<code>.247</code> is a second NIC or a second chassis is marked <code>[INFERENCE]</code> from ARP data;
and <code>/root/.ssh/authorized_keys</code> on Dankserver is not readable without a root shell.</li>
<li><strong>Method note.</strong> An unprivileged <code>ss</code> on a rootless-podman host hides most
listeners (they belong to <code>rootlessport</code>/<code>pasta</code>); every socket census here ran as
root, and the scan toolchain was installed on the audit box rather than the servers.</li>
</ul>
</section>
<footer>
Audit 2026-10-21 · read-only probes from blankpad against blankpad, Dankclaw, Dankserver and the LAN edge ·
part of <code>dank/command-center</code> · <code>omp-docs/reports/fleet-security-audit-2026-10-21.html</code>
</footer>
</div>
</body>
</html>