fix(actions): bound request body size in artifacts v4 twirp handlers (#39818)

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
This commit is contained in:
Shivansh Garg authored and GitHub committed 2026-10-17 10:40:04 +00:00
1 parent 3058f5ddf9
commit 0081bd8430
1 file changed
+10 -1
+10 -1
View File
@@ -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)