From 6195cda58f6b58c3544184c84dba99745e134ec8 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sat, 17 Oct 2026 23:17:45 -0700 Subject: [PATCH] fix(actions): bound request body size in artifacts v4 twirp handlers (#39818) (#39822) Backport #39818 by @SHIVANSHGARG07 parseProtobufBody read the full Twirp request body via io.ReadAll with no size limit, allowing an authenticated runner token holder to force unbounded memory allocation. Cap it at 1 MiB via io.LimitReader, matching the existing pattern in job_summary.go. Fixes https://github.com/go-gitea/gitea/issues/39814 Co-authored-by: Shivansh Garg --- routers/api/actions/artifactsv4.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go index a7befae91d8..93c892573d7 100644 --- a/routers/api/actions/artifactsv4.go +++ b/routers/api/actions/artifactsv4.go @@ -290,13 +290,22 @@ func (r *artifactV4Routes) findArtifactByName(ctx *ArtifactContext, runID int64, return &art, nil } +// maxProtobufBodySize caps the Twirp request body size accepted by parseProtobufBody. +// These requests only ever carry a handful of small scalar fields (run IDs, artifact +// names, etc.), so this is far above any legitimate payload while still bounding memory use. +const maxProtobufBodySize = 1024 * 1024 // 1 MiB + func (r *artifactV4Routes) parseProtobufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) bool { - body, err := io.ReadAll(ctx.Req.Body) + body, err := io.ReadAll(io.LimitReader(ctx.Req.Body, maxProtobufBodySize+1)) if err != nil { log.Error("Error decode request body: %v", err) ctx.HTTPError(http.StatusInternalServerError, "Error decode request body") return false } + if len(body) > maxProtobufBodySize { + ctx.HTTPError(http.StatusRequestEntityTooLarge, "request body too large") + return false + } err = protojson.Unmarshal(body, req) if err != nil { log.Error("Error decode request body: %v", err)