From 95a251e091954a50840edd6c40e03358c843d803 Mon Sep 17 00:00:00 2001 From: csd113 Date: Tue, 17 Mar 2026 21:20:20 -0700 Subject: [PATCH 1/8] Delete audit_report.md --- audit_report.md | 950 ------------------------------------------------ 1 file changed, 950 deletions(-) delete mode 100644 audit_report.md diff --git a/audit_report.md b/audit_report.md deleted file mode 100644 index 3195e08..0000000 --- a/audit_report.md +++ /dev/null @@ -1,950 +0,0 @@ -# RustChan — Comprehensive Security & Code Audit Report - -**Audited:** `src/` (Rust imageboard server) -**Date:** 2026-03-17 -**Auditor:** Static analysis + manual review - ---- - -## Summary - -| Severity | Count | -|----------|-------| -| **Critical** | 3 | -| **High** | 8 | -| **Medium** | 12 | -| **Low** | 11 | -| **Total** | **34** | - -**Overall assessment:** The codebase demonstrates strong security awareness — parameterized queries throughout, Argon2id password hashing, constant-time CSRF comparison, EXIF stripping, path-traversal guards, and extensive inline documentation of past fixes. However, several real production risks remain, including an unverified federation layer, a process-management bug that makes the ffmpeg timeout deceptive, and stored XSS via SVG uploads. - ---- - -## Complete Issue Index - -| # | Severity | Title | File | -|---|----------|-------|------| -| 12 | **Medium** | PoW nonce prune not rate-gated under concurrency | `utils/crypto.rs:~165` | -| 13 | **Medium** | `constant_time_eq` in posts.rs — use `subtle` crate | `db/posts.rs:~270` | -| 14 | **Medium** | `update_settings_file_site_names` matches comment lines | `config.rs:~320` | -| 15 | **Medium** | `admin_ban_and_delete` ban+delete not transactional | `handlers/admin/moderation.rs:~160` | -| 16 | **Medium** | Poll expiry not re-checked inside `cast_vote` | `db/posts.rs:cast_vote` | -| 17 | **Medium** | `has_recent_appeal` TOCTOU — no schema constraint | `db/admin.rs` | -| 18 | **Medium** | Gateway `insert_reply_into_thread` stores unescaped HTML | `db/chan_net.rs:~130` | -| 19 | **Medium** | Admin restore doesn't validate SQLite magic bytes | `handlers/admin/backup.rs` | -| 20 | **Medium** | Rate-limit IP hash uses hardcoded salt `"G"` not `cookie_secret` | `middleware/mod.rs:~155` | -| 21 | **Medium** | `thread_updates` builds JSON by string interpolation | `handlers/thread.rs:~360` | -| 22 | **Medium** | `Content-Disposition` header injection via `board` field | `chan_net/command.rs:140` | -| 23 | **Medium** | `pool_size` hardcoded despite comment claiming config | `db/mod.rs:143` | -| 24 | **Medium** | `classify_upload_error` fragile string-prefix matching | `handlers/mod.rs` | -| 25 | **Low** | `edit_post` `edit_window_secs=0` semantic mismatch | `db/posts.rs:~200` | -| 26 | **Low** | `delete_file` silently ignores filesystem errors | `utils/files.rs` | -| 27 | **Low** | `sanitize_filename` truncates by char count, not bytes | `utils/sanitize.rs` | -| 28 | **Low** | Tripcode uses unsalted SHA-256 | `utils/tripcode.rs` | -| 29 | **Low** | `ffmpeg` encoder detection makes 3 separate subprocess calls | `media/ffmpeg.rs` | -| 30 | **Low** | `encode_q` duplicated twice in backup.rs | `handlers/admin/backup.rs` | -| 31 | **Low** | `collect_thread_file_paths` unbounded SQLite variable count | `db/threads.rs:~75` | -| 32 | **Low** | `prune_login_fails` uses `Ordering::Relaxed` store | `handlers/admin/auth.rs:~83` | -| 33 | **Low** | Log file never rotated — will grow unbounded | `logging.rs:~35` | -| 34 | **Low** | `ACTIVE_IPS` prune clears entire map on first run after start | `server/server.rs:~305` | - ---- - -## Detailed Findings - ---- - -### [Critical] #1 — SVG Served Inline Without `Content-Disposition: attachment` - -**File:** `src/handlers/board.rs:753` and `src/utils/files.rs` (`detect_mime_type`) - -**Problem:** -SVG files are accepted as uploads (`image/svg+xml` is explicitly allowed in `detect_mime_type`) and served back with `Content-Type: image/svg+xml` inline via the `media_content_type()` map. An SVG file can contain `