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")
}