Fix SEC-05: add body size limit to REST API and max password length

- Wrap r.Body with http.MaxBytesReader (1 MiB) in decodeJSON so all
  REST API endpoints reject oversized JSON payloads
- Add MaxPasswordLen = 128 constant and enforce it in validate.Password()
  to prevent Argon2id DoS via multi-MB passwords
- Add test for oversized JSON body rejection (>1 MiB -> 400)
- Add test for password max length enforcement

Security: decodeJSON now applies the same body size limit the UI layer
already uses, closing the asymmetry. MaxPasswordLen caps Argon2id input
to a reasonable length, preventing CPU-exhaustion attacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 00:42:11 -07:00
parent 586d4e3355
commit 70e4f715f7
4 changed files with 54 additions and 2 deletions

View File

@@ -1269,9 +1269,21 @@ func writeJSON(w http.ResponseWriter, status int, v interface{}) {
}
}
// maxJSONBytes limits the size of JSON request bodies (1 MiB).
//
// Security (SEC-05): without a size limit an attacker could send a
// multi-gigabyte body and exhaust server memory. The UI layer already
// applies http.MaxBytesReader; this constant gives the REST API the
// same protection.
const maxJSONBytes = 1 << 20
// decodeJSON decodes a JSON request body into v.
// Returns false and writes a 400 response if decoding fails.
//
// Security (SEC-05): the body is wrapped with http.MaxBytesReader so
// that oversized payloads are rejected before they are fully read.
func decodeJSON(w http.ResponseWriter, r *http.Request, v interface{}) bool {
r.Body = http.MaxBytesReader(w, r.Body, maxJSONBytes)
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
if err := dec.Decode(v); err != nil {