HIGH regex dosgin

Regex Dos in Gin

How Regex Dos Manifests in Gin

Regex DoS (Denial of Service) attacks exploit the worst-case performance of certain regular expressions, causing catastrophic backtracking that can bring down your Gin application. In Gin's routing layer, regex patterns are commonly used for path parameters, middleware matching, and request validation.

The most vulnerable pattern in Gin is the use of nested quantifiers without proper anchors. Consider this Gin route definition:

router.GET("/user/:id", func(c *gin.Context) {
    // handler code
})

While this looks safe, if you modify it to use regex capture groups with nested quantifiers, you create a vulnerability:

router.GET("/user/:id([a-z]+)*", func(c *gin.Context) {
    // vulnerable handler
})

The pattern [a-z]+ inside (...)* creates exponential backtracking. An attacker can send requests like:

GET /user/aaa... (thousands of 'a' characters)

Gin's router will attempt to match this pattern, exploring every possible way to divide the string into groups, causing CPU usage to spike to 100%.

Another common Gin-specific scenario involves middleware that uses regex for path matching:

router.Use(gin.BasicAuth(gin.Accounts{
    "admin": "password",
}))

// Problematic: unanchored regex in middleware
router.GET("/admin/*path", gin.BasicAuth(gin.Accounts{
    "admin": "password",
}))

The *path wildcard can be exploited when combined with poorly constructed regex patterns in custom middleware. Attackers can craft requests that force the router to evaluate thousands of backtracking paths before rejecting the request.

Gin's gin.Context.Param() method can also be a vector when combined with regex extraction:

router.GET("/search/:query", func(c *gin.Context) {
    query := c.Param("query")
    // If query is used in regex operations without validation
    re := regexp.MustCompile("(a+)+b") // Vulnerable pattern
    re.MatchString(query)
    c.JSON(200, gin.H{"result": query})
})

This creates a double vulnerability: the router processes the path, then your handler processes the parameter with a vulnerable regex.

Gin-Specific Detection

Detecting Regex DoS in Gin applications requires both static analysis and runtime monitoring. Start with code review focusing on these Gin-specific patterns:

import (
    "regexp"
    "github.com/gin-gonic/gin"
)

// Vulnerable: nested quantifiers without anchors
var badPattern = regexp.MustCompile("(a+)+b")

func main() {
    router := gin.Default()
    
    // Check for problematic patterns in route definitions
    router.GET("/test/:id([a-z]+)*", vulnerableHandler)
    
    // Check middleware regex usage
    router.Use(authMiddleware())
    
    router.Run(":8080")
}

func vulnerableHandler(c *gin.Context) {
    id := c.Param("id")
    // This will cause catastrophic backtracking
    if badPattern.MatchString(id) {
        c.JSON(200, gin.H{"status": "ok"})
    }
}

func authMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // Check for unanchored patterns in path matching
        path := c.Request.URL.Path
        if match, _ := regexp.MatchString("(admin|user)+", path); match {
            // Processing logic
        }
    }
}

For automated detection, middleBrick's API security scanner includes specific checks for regex DoS patterns in Gin applications. It analyzes your OpenAPI/Swagger specs and runtime behavior to identify:

  • Nested quantifiers like (a+)+, (a*)*, (a+)*
  • Unanchored patterns that allow partial matches
  • Exponential patterns like (a+)+b or (a|a*)*
  • Backtracking-heavy alternations without proper ordering

middleBrick's scanner tests these patterns by sending crafted requests that trigger worst-case performance, measuring response times and CPU usage. The scanner specifically understands Gin's routing syntax and can identify vulnerable route patterns directly from your API definitions.

Runtime monitoring in production should track:

// Simple monitoring middleware for Gin
func regexDosMonitor() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        c.Next()
        duration := time.Since(start)
        
        // Flag requests taking suspiciously long
        if duration > 500*time.Millisecond && c.Request.Method == "GET" {
            log.Printf("Potential regex dos: %s %s took %v",
                c.Request.Method, c.Request.URL.Path, duration)
        }
    }
}

Integrate this with your Gin router to catch slow requests that might indicate regex exploitation attempts.

Gin-Specific Remediation

Remediating Regex DoS in Gin applications requires a multi-layered approach. Start by replacing vulnerable patterns with safer alternatives:

// Vulnerable pattern - DO NOT USE
badPattern := regexp.MustCompile("(a+)+b")

// Safe alternatives
// 1. Use possessive quantifiers (if supported) or atomic groups
// Go's regexp doesn't support possessive, so use alternatives:

// 2. Use bounded repetition with anchors
safePattern := regexp.MustCompile(`^a{1,100}b$`)

// 3. Use negative lookahead to prevent catastrophic backtracking
// This pattern matches 'a' followed by 'b' without backtracking
safePattern := regexp.MustCompile(`^(a+)b$`)

// 4. For complex patterns, use finite automata or state machines
// Instead of regex, use simple string operations when possible
func validateID(id string) bool {
    if len(id) > 100 {
        return false
    }
    // Simple character class check instead of regex
    for _, char := range id {
        if char < 'a' || char > 'z' {
            return false
        }
    }
    return true
}

// In your Gin handler
router.GET("/user/:id", func(c *gin.Context) {
    id := c.Param("id")
    if !validateID(id) {
        c.JSON(400, gin.H{"error": "invalid id"})
        return
    }
    // Safe processing
})

For route definitions in Gin, avoid complex regex patterns entirely:

// Instead of this (vulnerable)
router.GET("/user/:id([a-z]+)*", vulnerableHandler)

// Use simple path parameters
router.GET("/user/:id", func(c *gin.Context) {
    id := c.Param("id")
    // Validate length and character set manually
    if len(id) > 50 || !isValidID(id) {
        c.JSON(400, gin.H{"error": "invalid id"})
        return
    }
    c.JSON(200, gin.H{"id": id})
})

// Helper function for validation
func isValidID(id string) bool {
    if len(id) == 0 || len(id) > 50 {
        return false
    }
    for _, r := range id {
        if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && (r < '0' || r > '9') {
            return false
        }
    }
    return true
}

For middleware that needs pattern matching, use pre-compiled, anchored patterns:

var adminPathPattern = regexp.MustCompile(`^/admin(/|$)`)

func adminAuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        path := c.Request.URL.Path
        if adminPathPattern.MatchString(path) {
            // Admin authentication logic
            if !isAuthenticated(c) {
                c.JSON(401, gin.H{"error": "unauthorized"})
                c.Abort()
                return
            }
        }
        c.Next()
    }
}

Implement timeout protection for regex operations:

func safeMatch(pattern *regexp.Regexp, input string, timeout time.Duration) (bool, error) {
    result := make(chan bool, 1)
    var matched bool
    var err error
    
    go func() {
        matched = pattern.MatchString(input)
        result <- matched
    }()
    
    select {
    case matched = <-result:
        return matched, nil
    case <-time.After(timeout):
        return false, errors.New("regex timeout")
    }
}

// Usage in handler
router.GET("/search/:query", func(c *gin.Context) {
    query := c.Param("query")
    if len(query) > 200 {
        c.JSON(400, gin.H{"error": "query too long"})
        return
    }
    
    matched, err := safeMatch(safePattern, query, 100*time.Millisecond)
    if err != nil {
        c.JSON(500, gin.H{"error": "processing error"})
        return
    }
    
    if matched {
        c.JSON(200, gin.H{"result": "match"})
    } else {
        c.JSON(200, gin.H{"result": "no match"})
    }
})

Finally, integrate middleBrick's continuous monitoring to automatically scan your Gin APIs for regex DoS vulnerabilities. The Pro plan's continuous monitoring will catch new vulnerabilities introduced in code changes before they reach production.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Why are nested quantifiers in regex patterns dangerous for Gin applications?
Nested quantifiers like (a+)+ or (a*)* create exponential time complexity because the regex engine must explore every possible way to divide the input string among the groups. In Gin's routing layer, this means a single malicious request can cause the router to spend seconds or minutes processing, consuming 100% CPU and blocking other requests. The vulnerability is especially dangerous because Gin processes routes sequentially, so one slow regex can block the entire request processing pipeline.
How does middleBrick detect Regex DoS vulnerabilities in Gin applications?
middleBrick's scanner tests for regex DoS by sending crafted requests with long input strings designed to trigger worst-case backtracking scenarios. It measures response times, CPU usage, and memory consumption to identify patterns that exhibit exponential behavior. The scanner specifically understands Gin's routing syntax and can analyze OpenAPI/Swagger specs to find vulnerable route patterns. It also tests runtime behavior by sending requests that would cause catastrophic backtracking in common vulnerable patterns like (a+)+b or unanchored nested quantifiers.