Files
nexus/audits/20260616-1111-securityAudit.md
T
2026-06-16 11:51:07 +01:00

136 lines
6.0 KiB
Markdown

# Security Audit Report
## 1. Executive Summary
This fix-mode audit focused on file-reading and response-reading paths that could allocate complete files or unbounded remote bodies in memory.
The main risk fixed was local denial of service from large user-selected files, imported Leviathan artefacts, recordings, SSH key files, vault files, and remote update/GitHub API responses. Where the codebase already had a chunked document model, saves and exports now use it. Where a parser still requires a complete byte slice, the code now rejects oversized inputs before allocation.
Verification passed with targeted package tests, `go test ./...`, frontend regression tests, frontend build, and `git diff --check`.
## 2. Scope Reviewed
Reviewed and changed:
- Leviathan file-backed document save, case export, spectrogram image/audio conversion, PDF parsing, and BinSnoop file helpers.
- Wails API helpers that read SSH public keys and Leviathan image/audio inputs.
- SSH and VNC tunnel private-key loading.
- GitHub client and update-checker HTTP response handling.
- Recording playback parsing.
- Encrypted secrets vault loading.
Not live-tested:
- A packaged Wails desktop binary.
- Real remote SSH/VNC/GitHub endpoints.
- Very large real-world media corpora beyond automated guard tests.
## 3. Methodology
I searched for `ReadFile`, `ReadAll`, and whole-document `Range(0, size)` patterns, then classified each as chunked, bounded, embedded/test-only, or unsafe. Fixes were kept to low-risk local changes:
- Prefer `Document.ForEachChunk` for writing/exporting working file bytes.
- Stream line-oriented recordings with `bufio.Scanner`.
- Limit HTTP response reads with `io.LimitReader`.
- Add `os.Stat` size checks before unavoidable bounded `os.ReadFile` calls.
- Add parser-specific caps before whole-document reads.
## 4. Findings Summary
| ID | Severity | Confidence | Title | Component | Status |
|---|---:|---:|---|---|---|
| SEC-20260616-001 | Medium | High | Leviathan save/export and spectrogram tools could materialize large files | Leviathan API, spectrogram | Fixed |
| SEC-20260616-002 | Medium | High | Remote API/update responses were read without size limits | GitHub client, updater | Fixed |
| SEC-20260616-003 | Medium | High | Local app data/key reads lacked size caps | SSH keys, VNC keys, vault, BinSnoop | Fixed |
| SEC-20260616-004 | Low | High | Recording playback loaded the whole capped recording file | Recording playback | Fixed |
| SEC-20260616-005 | Low | Medium | Some parsers still require complete bounded buffers | PDF, cert/key scanners, media decoders | Accepted with caps |
## 5. Detailed Findings
### SEC-20260616-001: Leviathan full-file allocation paths
Leviathan save/export and spectrogram operations could duplicate entire working files in memory. Case export also built the zip archive in memory before writing it.
Fixed in:
- `internal/api/leviathan.go`
- `internal/leviathan/spectrogram/spectrogram.go`
- `internal/leviathan/pdf/pdf.go`
Changes:
- Working-copy save writes via `Document.ForEachChunk`.
- Case export streams `working.bin` directly into `zip.Writer` backed by the destination file.
- Spectrogram encode/view/insert rejects oversized image/audio documents before bounded decode.
- Image decoding checks compressed byte size and decoded pixel dimensions before full image decode.
- PDF parsing rejects files above 128 MiB before whole-document structural parsing.
- Long-running spectrogram/export tools no longer hold the Leviathan engine lock while doing heavy work or native save dialogs.
### SEC-20260616-002: Unbounded remote response reads
GitHub and update-check response bodies could be read without an explicit maximum.
Fixed in:
- `internal/githubclient/githubclient.go`
- `internal/updater/updater.go`
Changes:
- GitHub JSON responses are capped at 4 MiB.
- GitHub error bodies are capped at 64 KiB.
- Update release/manifest responses are capped at 1 MiB.
- Repository archive downloads continue to stream to disk instead of memory.
### SEC-20260616-003: Local key/vault/helper reads lacked caps
Several local helper paths read files directly even though the expected files are small.
Fixed in:
- `internal/api/api.go`
- `internal/sshclient/sshclient.go`
- `internal/sessions/manager.go`
- `internal/secrets/secrets.go`
- `internal/leviathan/binsnoop/common.go`
- `internal/leviathan/binsnoop/binsnoop.go`
Changes:
- SSH public keys are capped at 64 KiB.
- SSH private keys for SSH and VNC tunnel auth are capped at 1 MiB.
- Secret vault files are capped at 10 MiB.
- BinSnoop direct file helpers are capped at 64 MiB; the UI path already uses a bounded buffer.
### SEC-20260616-004: Recording playback whole-file read
Recording playback had a 100 MiB file cap, but still read and split the full file in memory.
Fixed in:
- `internal/recording/recorder.go`
Changes:
- Playback now opens the recording and scans line-by-line.
- Individual playback lines are capped at 8 MiB.
- Existing malformed-event tolerance is preserved.
## 6. Residual Risk
Some operations still need bounded complete buffers because downstream parsers or decoders require byte slices: image/audio spectrogram conversion, PDF structural parsing, certificate/key scanning, and small SSH/vault/public-key parsing. These now fail before allocation when inputs exceed explicit caps.
Truly streaming versions of every binary parser would be a larger Leviathan architecture project. The current fixes remove the unbounded allocation behavior while preserving tool behavior for normal files.
## 7. Verification
Passed:
- `go test ./internal/api ./internal/leviathan/spectrogram ./internal/leviathan/pdf ./internal/leviathan/binsnoop ./internal/updater ./internal/githubclient ./internal/secrets ./internal/recording ./internal/sshclient ./internal/sessions -count=1`
- `go test ./... -count=1`
- `npm --prefix frontend test`
- `npm --prefix frontend run build`
- `git diff --check`
New tests cover oversized GitHub/update bodies, oversized spectrogram images, bounded Leviathan document reads, chunked patched-file writes, oversized public keys, oversized vault files, oversized PDFs, and BinSnoop file caps.