8.4 KiB
VULNS.md — Known & Historically Found Vulnerabilities
Registry of security findings for Brain of Reese. Full details, proofs of
concept, and the priority-ordered remediation task list live in
.agents/remediation_plan.md (this file is the
quick-reference index; when a finding is fixed, update its status here and
append to the fixed log at the bottom).
Conventions:
- Statuses:
open→mitigated(control in place) →fixed(remediated + verified) →accepted(owner decision, risk consciously kept) →false positive(intended behavior — never re-raise or "fix" without an explicit owner decision). - Prior-audit IDs keep their original numbering (SEC-0x = audit 2026-09-07, SEC-14-xx = audit 2026-09-14).
Open findings
| ID | Sev | Type (CWE) | Location | Status |
|---|---|---|---|---|
| SEC-14-04 | Medium | In-flight SSE chat stream pins a DB connection for the whole turn → pool-exhaustion DoS (~15 streams, one token user) (CWE-770/400) | app/api/chat.py (request-scoped get_db across the StreamingResponse), app/db.py (default pool 5+10) |
open |
SEC-14-04 — one-line essence: 16 slow curl -N streams on /api/chat
with any token hang every DB-backed route (default pool = 15 connections).
Remediation: short-lived sessions per DB step inside the stream (the
sync/upload house pattern), explicit pool kwargs, optional chat concurrency
cap — see .agents/remediation_plan.md §SEC-14-04.
False positives — 2026-09-14 audit (owner: intended behavior, well known)
Reclassified by the owner on 2026-09-14: every 2026-09-14 finding except SEC-14-04 is intended, well-known behavior of a single-owner homelab app — not a vulnerability to remediate. Kept here for the record so a future audit (or a future agent) does not re-raise them. Do NOT "fix" these without an explicit owner decision; the trade-offs below are deliberate.
| ID | Sev (as audited) | Type (CWE) | Location | Why it's intended |
|---|---|---|---|---|
| SEC-14-01 | Medium | Unthrottled anonymous write surface → storage-exhaustion DoS (CWE-770/307) | app/api/chats.py (public POST/PUT /api/chats, POST /{id}/share); app/core/rate_limit.py covers login routes only |
Public chat-save is the owner-locked phase-55 A1 design (the visitor saves their own conversation; auto-save is a normal traffic path). Homelab LAN trust model. |
| SEC-14-02 | Medium | Guest IDOR — chat-id holder can force-share / overwrite a private chat (CWE-639) | app/api/chats.py share_chat, update_chat |
Owner-locked trust model: the unguessable uuid4 row id IS the credential (phase 51/55). Sharing/overwriting by an id holder is intended. |
| SEC-14-03 | Medium | Postgres on 0.0.0.0:5432 with weak documented creds reese:reese (CWE-790/668) |
compose.yaml (db ports, POSTGRES_PASSWORD), app/config.py default database_url, .env.example |
Deliberate homelab dev convenience; the trusted LAN is the security boundary and the creds are documented on purpose. |
| SEC-14-05 | Low | Cleartext transport + plaintext admin password (CWE-319/256) | app/main.py (https_only=False), app/config.py |
Owner decision 2026-08-22: plaintext password and homelab HTTP are deliberate (TLS is a documented non-goal). |
| SEC-14-06 | Low | debugpy binds 0.0.0.0:5678 when DEBUGPY=1 → LAN RCE if left on (CWE-1188) |
app/core/debugging.py |
Explicit opt-in dev feature (AGENTS.md rule 7); the wide bind is intentional for remote IDE attach. |
| SEC-14-07 | Low | No throttle on /api/chat for token users — leaked token = unlimited LLM turns (CWE-770) |
app/api/chat.py, app/rag/llm.py |
Tokens are capability credentials by design (phase 79); holders are trusted to use the models. |
| SEC-14-08 | Low | Importer reads source files whole, no per-file size cap (git/local sources; uploads are capped) (CWE-770) | app/rag/importer.py:390 |
Source dirs are admin-chosen trusted content; the never-truncated A7 contract implies whole-file reads. |
| SEC-14-09 | Low | Full question text + tool args in stdout logs and query_log (CWE-532) |
app/api/chat.py per-turn line, app/rag/agent.py tool line |
The full per-turn log line is a locked PLAN §9 requirement (AGENTS.md rule 10: "amply log"). |
| SEC-14-10 | Info | Admin git-source registry reaches arbitrary https/ssh/git@ hosts (admin-gated SSRF) (CWE-918) | app/api/git_sources.py URL_RE → scripts/git_sync.py |
Admin-only surface; the admin already controls the host. Arbitrary remotes are the feature (phase 59/35). |
| SEC-14-11 | Info | No Referrer-Policy / Permissions-Policy (owner decision A4, phase 82) (CWE-538) |
app/core/security_headers.py |
Phase-82 decision A4 deliberately scoped headers to CSP + XFO + nosniff; no external requests exist (No-CDN). |
| SEC-14-12 | Info | BOR_SESSION_SECRET only checked non-empty — weak secret allows cookie forgery (CWE-340) |
app/core/auth.py ensure_admin_configured |
Operator-provisioned secret (generator command documented in .env.example); strength is the operator's choice. |
Note: .agents/remediation_plan.md (the audit report) still lists these with
remediation tasks — its task list items P1 (parts), P2, P4, P5, P6, P7
address findings now reclassified as false positives and are dropped
unless the owner reopens them. Only task P3 (SEC-14-04) remains actionable.
Fixed (verified present in the 2026-09-14 audit)
| ID | Sev | What it was | Fixed by | Fixed phase |
|---|---|---|---|---|
| SEC-03 | Medium | No rate limit on failed sign-ins (/api/login, /api/token-auth) |
Per-IP sliding window (10 fails / 15 min, shared counter, fail-open) — app/core/rate_limit.py |
81 |
| SEC-04 | Medium | No CSP / X-Frame-Options / nosniff → clickjacking of the admin UI | SecurityHeadersMiddleware — CSP default-src 'self'; base-uri 'none'; frame-ancestors 'none' + X-Frame-Options: DENY + nosniff on every response |
82 |
| SEC-05 | Medium | Unbounded anonymous payload on the public chat-save surface | Schema caps: ≤200 messages, 32 KB text/thinking, nested list caps (~13 MB worst-case) — app/schemas.py |
83 |
| SEC-08 | Medium | Docs-push 502 leaked git stderr with user:pass@ credentials |
app/core/errors.sanitize_error userinfo masker applied to all error surfaces |
84 |
| SEC-13 | Low | LLM error strings interpolated the raw base URL (possible embedded creds) | Same sanitizer on every LLM error f-string | 84 |
Controls verified sound (2026-09-14 audit — no finding)
- SQL injection: all ORM / parameter-bound
text(); FTS tsquery regex-constrained to[a-z0-9.]and bound as a parameter. - XSS: escape-first
renderMarkdown(),textContentfor all data, strict CSP, nounsafe-inline(theme tag uses a sha256-hashed style-src exemption), allinnerHTMLsites audited static-or-escaped. - Command injection: single list-argv subprocess funnel (
scripts/git_sync.run_git), noshell=True; branch tokens shape-validated at boot; draft paths refuse absolute/... - Archive upload: traversal / absolute / drive-letter / symlink-hardlink escape / device-FIFO rejection, compressed + extracted byte caps (zip-bomb), atomic swap-in with rollback —
app/rag/archive_upload.py. - API tokens: 128-bit CSPRNG, SHA-256 hash stored (plaintext one-shot in the 201 body only), per-request live row check = revocation, generic 401s (no enumeration).
- Open redirect: login
?next=restricted to same-origin relative paths. - Agent tools: model-supplied
ls/read/grepresolve against Postgres rows only (no FS/network), round cap bounds loops, fixed-substring grep (no ReDoS). - Dependencies:
pip-auditclean on the locked set (2026-09-14); bandit hits are false positives / dev scripts. - Git history: no committed secrets across all 161 commits (2026-09-14 scan);
.envgitignored.
Re-audit triggers
Re-run the audit (or at least the relevant lens) when any of these land:
a reverse proxy or TLS in front of the app, a multi-user/auth rework,
changes to app/api/chats.py write gating, the compose port bindings, the
subprocess/git surface, the upload pipeline, or any dependency with a
published CVE (uvx pip-audit).
Changelog
- 2026-09-14 (owner reclassification) — all 2026-09-14 findings except SEC-14-04 reclassified as false positives (intended behavior, well known). Open count: 12 → 1.
- 2026-09-14 — second audit: 12 new findings (4 Medium / 4 Low / 4 Info),
5 prior findings verified fixed. Full report:
.agents/remediation_plan.md.