mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: enforce max body size on CSP violation report endpoint (#27243)
The `/api/v2/csp/reports` endpoint is unauthenticated and CSRF-exempt, since it's the browser's `report-uri` target, and decoded request bodies with no size limit. This let an attacker post arbitrarily large JSON bodies to force unbounded heap allocation and OOM the server (Cure53 CDM-02-007). Wraps the request body in `http.MaxBytesReader` before decoding and returns 413 when the limit is exceeded, matching the existing convention used by `files.go`, `aitasks.go`, and `exp_chats.go`. Fixes: https://github.com/coder/security-disclosures/issues/171
This commit is contained in:
@@ -2,6 +2,8 @@ package coderd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"cdr.dev/slog/v3"
|
||||
@@ -9,6 +11,12 @@ import (
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
// cspReportMaxBytes bounds the size of a single CSP violation report. This
|
||||
// endpoint is unauthenticated and CSRF-exempt (it's the browser's
|
||||
// `report-uri` target), so it must not allow unbounded body sizes to reach
|
||||
// json.Decode. Real CSP reports are small JSON objects; 64KB is generous.
|
||||
const cspReportMaxBytes = 64 * 1024
|
||||
|
||||
type cspViolation struct {
|
||||
Report map[string]interface{} `json:"csp-report"`
|
||||
}
|
||||
@@ -22,14 +30,23 @@ type cspViolation struct {
|
||||
// @Tags General
|
||||
// @Param request body cspViolation true "Violation report"
|
||||
// @Success 200
|
||||
// @Failure 413 {object} codersdk.Response
|
||||
// @Router /api/v2/csp/reports [post]
|
||||
func (api *API) logReportCSPViolations(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var v cspViolation
|
||||
|
||||
r.Body = http.MaxBytesReader(rw, r.Body, cspReportMaxBytes)
|
||||
dec := json.NewDecoder(r.Body)
|
||||
err := dec.Decode(&v)
|
||||
if err != nil {
|
||||
if _, ok := errors.AsType[*http.MaxBytesError](err); ok {
|
||||
httpapi.Write(ctx, rw, http.StatusRequestEntityTooLarge, codersdk.Response{
|
||||
Message: "Request body too large.",
|
||||
Detail: fmt.Sprintf("Maximum CSP report size is %d bytes.", cspReportMaxBytes),
|
||||
})
|
||||
return
|
||||
}
|
||||
api.Logger.Warn(ctx, "CSP violation reported", slog.Error(err))
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to read body, invalid json.",
|
||||
|
||||
Reference in New Issue
Block a user