14-application-security.md
markdown
sha256:7d5985ef251de9f0154f9b185a75cf36174bf73e0c34f5eca133e7bd20224bf4
Merge branch 'feat/opengraph-repo-cards' into dev
Human
22 days ago
Section 14 — Application Security
Companion to
musehub-production-readiness-checklist.md.
✅ Fixed — /_debug/memory was exposed unconditionally in production
musehub/main.py registered /_debug/memory (live RSS + tracemalloc top allocations) without
the if settings.debug: guard that correctly protects /docs and /redoc in the same file —
reachable by anyone in production, no auth check. Fixed in this session by wrapping the route
registration in the same if settings.debug: guard used elsewhere in the file. Deployed to
staging/production whenever the next regular deploy runs.
What's already solid — confirmed by code review
- No SQL injection surface found. No raw string-formatted SQL anywhere in
musehub/(grepped forf"..."/.format()/%patterns near SQL keywords — none found outside an unrelated file-write). The app uses SQLAlchemy's ORM/parameterized queries throughout. - Path traversal explicitly rejected in the coordination module — opaque alphanumeric ID validation with an explicit comment noting traversal-char rejection.
- Archive/decompression bomb protection exists:
mpack_max_decompressed_bytes(4 GB cap) inmusehub/config.py— mpacks are quarantined if decompressed size exceeds this, directly answering the checklist's "protect against unsafe archive extraction." - No SSRF-prone outbound URL fetching found in the app's request-handling code (grepped for
httpx.get/requests.get/etc. — none matched);musehub/worker.py's Cloudflare Worker interaction wasn't independently reviewed for this in this pass, worth a closer look given it's the one component that talks to an external URL. - Debug mode is off by default (
debug: bool = FalseinSettings), and/docs//redocare correctly registered onlyif settings.debug:— Swagger/ReDoc won't leak in production. - MSign auth is well-implemented for privileged actions:
musehub/api/routes/mcp.pyrequires a fresh signed request (not just a valid session) for sensitive tool calls — this directly satisfies "verify privileged actions require fresh authorization," which most apps get wrong. - No passwords stored anywhere — MSign is signature-based, so "secure password hashing," "email verification," and "secure account recovery" (as password-reset-flow concepts) are N/A. Account recovery in this model is really "recover your Ed25519 key," which is covered by the mnemonic-backup flow documented in the global ecosystem guide, not by this app.
- Rate limiting on auth-adjacent endpoints: confirmed in Section 5 (
slowapilimits, bot throttling exempting only authenticated MSign traffic). - CORS fails closed:
cors_origins: list[str] = []by default, with an explicit warning log if a wildcard is ever configured alongsidedebug=false. - Security headers and CSP already set (Section 5):
X-Frame-Options,X-Content-Type-Options, CSP, HSTS. - Upload limits exist:
mpack_max_bytes(512 MB),mpack_max_commits(100k),mpack_max_objects(1M), per-user (10 GB) and per-repo (5 GB) quotas, per-user daily upload cap (50 GB) — thorough, deliberate limits, not just a single blanket body-size cap.
Gaps / not reviewed in this pass
- [ ] CSRF protection — not reviewed; likely lower risk given no cookie-based sessions exist (MSign is header-based, not vulnerable to classic CSRF the way cookie auth is), but not explicitly confirmed for any state-changing endpoint that might still rely on ambient browser credentials
- [ ] Uploaded content scanning (malware/content scanning beyond size/structure limits) — not done
- [ ] WebSocket/SSE authentication — MCP/SSE endpoints exist (3600s timeouts, Section 5); auth model for the streaming case specifically wasn't independently verified in this pass
- [ ] Data classification and retention — not documented
- [ ] Account and data deletion path — not verified whether one exists
- [ ] OWASP-oriented review — this pass covers several OWASP Top 10 categories (injection, broken auth, security misconfiguration via the debug-endpoint finding) but isn't a formal OWASP pass
- [ ] Session expiration / token revocation — N/A in the traditional sense (no sessions); MSign
signatures are per-request and time-stamped (
ts=...), which is a different but likely equivalent guarantee — not independently verified for replay-window correctness in this pass
The actual work items here
- Fix
/_debug/memory's missing guard — small, fast, real fix. - Review
musehub/worker.py's outbound Cloudflare Worker calls for SSRF exposure specifically. - Confirm MSign's timestamp/replay-window logic (
ts=...in the signature) actually prevents replay attacks, not just informs logging. - Do a dedicated OWASP-oriented pass closer to launch (Section 17), building on this section's findings rather than starting cold.
File History
1 commit
sha256:be1b2fdf6ab1fc652b3b35a945d0277a36fbf5d96e63692020d36cd7ebe03534
Merge 'docs/security-monitoring-verified' into 'dev' — prop…
Human
2 days ago