Unrestricted Resource Consumption

Unrestricted Resource Consumption in Go Gin [Apr 2026] [CVE-2026-34166]

[Updated Apr 2026] Updated CVE-2026-34166

Overview

Unrestricted Resource Consumption (URC) vulnerabilities allow an attacker to exhaust memory or CPU by forcing heavy processing on the server. The real-world CVE CVE-2026-34166 (LiquidJS) shows how a templating engine can miscalculate memory usage when a memory limiter is enabled, charging output in a way that dramatically underestimates actual usage and enabling approximately 2,500x amplification, potentially causing out-of-memory conditions. This vulnerability is CWE-400 (Unrestricted Resource Consumption) and demonstrates how miscalculated growth in output can be exploited via crafted template content.

Code Fix Example

Go (Gin) API Security Remediation
package main

import (
  "fmt"
  "net/http"
  "strings"
  "github.com/gin-gonic/gin"
)

type Payload struct {
  Text  string `json:"text" binding:"required"`
  Times int    `json:"times" binding:"required"`
}

const maxOutputSize = 1 << 20 // 1 MB max output from the fixed path

// Vulnerable rendering: unbounded memory growth by concatenating input Times times
func vulnerableRender(text string, times int) string {
  var b strings.Builder
  for i := 0; i < times; i++ {
    b.WriteString(text)
  }
  return b.String()
}

// Fixed rendering: guard against excessive output sizes
func safeRender(text string, times int, maxSize int) (string, error) {
  if times < 0 {
    times = 0
  }
  // Quick guard against huge allocations
  if maxSize > 0 && len(text)*times > maxSize {
    return "", fmt.Errorf("requested output too large: %d bytes", len(text)*times)
  }
  var b strings.Builder
  b.Grow(len(text) * times)
  for i := 0; i < times; i++ {
    b.WriteString(text)
  }
  return b.String(), nil
}

func limitBodySize(maxBytes int64) gin.HandlerFunc {
  return func(c *gin.Context) {
    c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxBytes)
  }
}

func main() {
  r := gin.Default()
  // Limit request body size to prevent very large inputs
  r.Use(limitBodySize(1 << 20)) // 1 MB

  // Vulnerable endpoint: demonstrates potential DoS via unbounded growth
  r.POST("/vuln/render", func(c *gin.Context) {
    var p Payload
    if err := c.ShouldBindJSON(&p); err != nil {
      c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
      return
    }
    // This can allocate a huge string if p.Times is large
    res := vulnerableRender(p.Text, p.Times)
    c.String(http.StatusOK, res)
  })

  // Fixed endpoint: enforces a maximum output size
  r.POST("/fix/render", func(c *gin.Context) {
    var p Payload
    if err := c.ShouldBindJSON(&p); err != nil {
      c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
      return
    }
    res, err := safeRender(p.Text, p.Times, maxOutputSize)
    if err != nil {
      c.JSON(http.StatusRequestEntityTooLarge, gin.H{"error": err.Error()})
      return
    }
    c.String(http.StatusOK, res)
  })

  // Start server
  r.Run(":8080")
}

CVE References

Choose which optional cookies to allow. You can change this any time.