Skip to content

Commit 79ec166

Browse files
committed
version bump to v1.0.11
1 parent f4c00d2 commit 79ec166

2 files changed

Lines changed: 83 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,88 @@
22

33
All notable changes to RustChan will be documented in this file.
44

5-
## [1.0.10] — 2026-03-06
5+
## [1.0.11] — 2026-03-06
6+
7+
### Security — Critical
8+
9+
- **CRIT-1: Security headers** — added `Content-Security-Policy`, `Strict-Transport-Security`,
10+
and `Permissions-Policy` response headers to `build_router()`. CSP restricts scripts, styles,
11+
and media to `'self'`, preventing external payload loading or data exfiltration via XSS.
12+
HSTS enforces HTTPS for one year including subdomains. Permissions-Policy disables
13+
camera, microphone, and geolocation APIs.
14+
15+
- **CRIT-2: Proxy-aware IP extraction in post handlers** — all post-creation handlers
16+
(`create_thread`, `post_reply`) now use the proxy-aware `extract_ip()` / `ClientIp` extractor
17+
instead of the raw socket address. Bans and rate limits are now effective when the server
18+
runs behind nginx or any other reverse proxy.
19+
20+
- **CRIT-3: Rate limiting on GET endpoints** — the catalog, search, thread-update, and JSON
21+
API endpoints were previously completely unrate-limited, allowing trivial DoS via unbounded
22+
LIKE scans or 200-thread catalog loads. A separate GET rate limiter (60 req/min per IP)
23+
has been applied to all read-heavy routes.
24+
25+
- **CRIT-4: Zip-bomb protection on restore handlers** — all four backup restore handlers
26+
previously used `std::io::copy` with no size or entry limits. Each entry is now capped at
27+
1 GiB via `.take()` and extraction aborts if more than 50 000 entries are encountered,
28+
preventing a 1 KB zip from exhausting disk space.
29+
30+
- **CRIT-5: IP address hashing** — raw IP addresses are no longer stored in the `ACTIVE_IPS`
31+
`DashMap` or printed to stdout/logs. All IP tracking now uses the same HMAC-keyed hash
32+
(`hash_ip`) used elsewhere, preventing IP exposure in coredumps or log aggregators.
33+
34+
- **CRIT-6: Admin login brute-force lockout** — the admin login endpoint previously had no
35+
per-IP failure tracking beyond the global rate limit (~600 attempts/hour). Failed login
36+
attempts are now counted per IP and the account is locked for a progressive delay after
37+
5 consecutive failures.
38+
39+
- **CRIT-7: Constant-time CSRF token comparison** — CSRF token validation was using
40+
standard `==` string comparison, leaking prefix-matching information via timing side
41+
channel. Comparison now uses `subtle::ct_eq` for constant-time equality.
42+
43+
- **CRIT-8: Poll input length and count caps** — poll questions and options had no
44+
server-side limits, allowing megabytes of text or thousands of options per submission.
45+
Poll options are now capped at 10, each option at 128 characters, and the question
46+
at 256 characters.
47+
48+
### Security — High
49+
50+
- **HIGH-1: Admin session cookie `Max-Age`** — the session cookie previously had no
51+
`Max-Age` or `Expires` attribute, causing browsers to persist it indefinitely after the
52+
tab was closed. The cookie now carries a `Max-Age` matching the server-side
53+
`session_duration` config value.
54+
55+
- **HIGH-2: Database connection pool timeout** — the r2d2 connection pool had no
56+
acquisition timeout, allowing `spawn_blocking` threads to block forever under load and
57+
exhaust the Tokio thread pool. A 5-second `connection_timeout` has been added to the
58+
pool builder.
59+
60+
- **HIGH-3: Per-route body limits on small-payload endpoints** — the global 50 MiB
61+
`DefaultBodyLimit` was applied to every route including login, vote, report, and appeal,
62+
causing the server to buffer 50 MiB before returning 400 on oversized requests. These
63+
four endpoints now carry an explicit 64 KiB per-route limit.
64+
65+
- **HIGH-4: Open redirect hardening on `return_to`** — the logout `return_to` parameter
66+
check only blocked `//` and `..`, allowing backslash (`\`) and URL-encoded variants
67+
(`%5C`) to redirect to external hosts on some browsers. The filter now also rejects any
68+
value containing a literal backslash or its percent-encoded form.
69+
70+
- **HIGH-5: Proxy-aware IP in `file_report` and `submit_appeal`** — these two handlers
71+
were using the raw socket IP for per-IP rate limiting, making the limit ineffective
72+
behind a reverse proxy. Both now use the `ClientIp` extractor, consistent with post
73+
handlers (same root cause as CRIT-2).
74+
75+
- **HIGH-6: Exponential backoff with jitter in worker error recovery** — all four
76+
background workers recovered from DB errors with a flat 2-second sleep, meaning all
77+
workers could retry simultaneously and storm the database. Error recovery now uses
78+
exponential backoff (500 ms base, doubling per failure, capped at 60 s) with 0–500 ms
79+
random jitter to spread retries across workers.
80+
81+
- **HIGH-7: TOCTOU race in file deduplication** — concurrent identical uploads could both
82+
pass the hash check before either had written to `file_hashes`, causing the second
83+
`record_file_hash` call to return a 500. The insert now uses `INSERT OR IGNORE` so the
84+
second concurrent insert is silently a no-op instead of an error.
85+
86+
687

788
### Added
889
- **Per-post inline ban+delete** — the admin toolbar that appears on every post in

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rustchan"
3-
version = "1.0.10"
3+
version = "1.0.11"
44
edition = "2021"
55
license = "MIT"
66
# FIX[LOW-1]: Removed hardware-specific description. This binary is portable

0 commit comments

Comments
 (0)