Regex Dos in Echo Go
How Regex Dos Manifests in Echo Go
Regular expression denial of service (ReDoS) attacks exploit catastrophic backtracking in poorly constructed regex patterns, causing exponential time complexity that can bring applications to a halt. In Echo Go, this vulnerability commonly manifests in several critical areas.
Route parameter validation is a primary attack vector. Echo's default parameter binding uses regex patterns for path parameters, and developers often add custom validation patterns without considering performance implications. Consider this vulnerable route:
e.GET("/user/:id", func(c echo.Context) error {
id := c.Param("id")
// Process user ID
return c.JSON(http.StatusOK, map[string]string{"id": id})
})
While seemingly harmless, Echo allows regex constraints on parameters:
e.GET("/user/:id[\d+]", func(c echo.Context) error {
// Vulnerable to ReDoS if pattern is complex
return c.JSON(http.StatusOK, map[string]string{"id": c.Param("id")})
})
The real danger emerges when developers add validation middleware with complex patterns:
func validateUUID(c echo.Context) error {
uuid := c.Param("uuid")
// Vulnerable pattern - exponential backtracking
matched, _ := regexp.MatchString(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, uuid)
if !matched {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid UUID")
}
return nil
}
e.GET("/resource/:uuid", validateUUID, handler)
Input validation in Echo middleware presents another attack surface. Developers frequently use regex for input sanitization without realizing the performance implications:
func sanitizeInput(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
input := c.FormValue("data")
// Vulnerable pattern - catastrophic backtracking
clean := regexp.MustCompile(`[a-zA-Z0-9.,;:!? ]+`).ReplaceAllString(input, "")
c.Set("cleanData", clean)
return next(c)
}
}
JSON body parsing with regex validation creates particularly dangerous scenarios. When Echo binds JSON to structs with validation tags, complex patterns can trigger ReDoS:
type User struct {
Email string `json:"email" validate:"email"`
Password string `json:"password" validate:"password"`
}
// Vulnerable validation patterns
func (u *User) Validate() error {
if !regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`).MatchString(u.Email) {
return errors.New("invalid email")
}
// Complex password pattern with nested quantifiers
if !regexp.MustCompile(`^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$`).MatchString(u.Password) {
return errors.New("weak password")
}
return nil
}
The most severe Echo-specific manifestation occurs in route group validation. When multiple routes share validation middleware with complex regex patterns, a single malicious request can affect the entire route group's performance:
g := e.Group("/api/v1")
g.Use(validateWithComplexRegex)
g.GET("/users/:id", getUser)
g.POST("/users", createUser)
g.PUT("/users/:id", updateUser)
In this setup, a ReDoS attack on any route in the group can degrade performance across all routes, creating a cascading failure scenario unique to Echo's middleware architecture.
Echo Go-Specific Detection
Detecting ReDoS vulnerabilities in Echo Go applications requires a multi-faceted approach combining static analysis, runtime monitoring, and specialized security scanning.
Static analysis tools can identify suspicious regex patterns in Echo applications. Look for these red flags in your codebase:
# Search for vulnerable patterns
grep -r "regexp\.MustCompile" . --include="*.go" | grep -E "(\*\+|\{\d+,\}|\(\?\:.*)"
# Find all regex usage in Echo middleware
grep -r "\.Use(" . --include="*.go" | xargs grep -l "regexp"
Runtime monitoring provides real-time detection of ReDoS attacks. Implement request timing middleware to identify suspicious patterns:
func requestTimer(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
start := time.Now()
err := next(c)
duration := time.Since(start)
// Flag requests taking suspiciously long
if duration > 500*time.Millisecond {
log.Printf("Slow request: %s %s took %v", c.Request().Method, c.Path(), duration)
// Consider adding rate limiting or blocking
}
return err
}
}
e.Use(requestTimer)
middleBrick's API security scanner specifically detects ReDoS vulnerabilities in Echo Go applications. The scanner analyzes your API endpoints for regex-related security issues:
# Scan Echo Go API for regex vulnerabilities
middlebrick scan https://yourapi.com
The scanner identifies problematic patterns including nested quantifiers, overlapping alternations, and backtracking-prone constructs. It specifically tests for:
- Catastrophic backtracking in route parameter validation
- Exponential time complexity in input validation middleware
- Resource exhaustion in JSON body parsing with regex tags
- Shared middleware group vulnerabilities
middleBrick provides detailed reports with severity levels and specific remediation guidance for each detected issue. The scanner's continuous monitoring capability (Pro plan) can alert you when new regex vulnerabilities are introduced in your codebase.
Unit testing with pathological inputs helps validate regex performance. Create test cases that trigger worst-case behavior:
func TestRegexPerformance(t *testing.T) {
// Pathological input that triggers exponential backtracking
maliciousInput := strings.Repeat("a", 1000) + "b"
start := time.Now()
matched := regexp.MustCompile(`a*a*a*a*a*a*a*a*a*a*b`).MatchString(maliciousInput)
duration := time.Since(start)
if duration > 100*time.Millisecond {
t.Errorf("Regex took too long: %v", duration)
}
if !matched {
t.Error("Regex should match")
}
}
Performance profiling tools like pprof can help identify regex-related CPU bottlenecks in production Echo applications. Monitor CPU usage during regex operations to detect potential ReDoS conditions.
Echo Go-Specific Remediation
The most effective remediation is replacing vulnerable regex patterns with safer alternatives. For common validation scenarios, use predefined patterns or libraries:
// Instead of complex email regex
import "github.com/go-playground/validator/v10"
func validateEmail(email string) bool {
v := validator.New()
return v.Var(email, "email") == nil
}
// Safer UUID validation using string length and character checks
func validateUUID(uuid string) bool {
if len(uuid) != 36 {
return false
}
// Simple character validation without backtracking
for i, char := range uuid {
switch i {
case 8, 13, 18, 23:
if char != '-' { return false }
default:
if !((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f')) {
return false
}
}
}
return true
}
For input validation, prefer explicit character checking over regex:
func sanitizeInput(input string) string {
var result []rune
for _, char := range input {
if (char >= 'a' && char <= 'z') ||
(char >= 'A' && char <= 'Z') ||
(char >= '0' && char <= '9') ||
char == '.' || char == ',' || char == ' ' {
result = append(result, char)
}
}
return string(result)
}
In Echo middleware, implement timeout protection for regex operations:
func safeRegexMatch(pattern, input string, timeout time.Duration) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
matched := make(chan bool)
go func() {
matched <- regexp.MustCompile(pattern).MatchString(input)
}()
select {
case result := <-matched:
return result, nil
case <-ctx.Done():
return false, errors.New("regex timeout")
}
}
// Use in middleware
func validateWithTimeout(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
input := c.FormValue("data")
valid, err := safeRegexMatch(`[a-zA-Z0-9]+`, input, 100*time.Millisecond)
if err != nil {
return echo.NewHTTPError(http.StatusRequestTimeout, "Validation timeout")
}
if !valid {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid input")
}
return next(c)
}
}
For Echo route parameter validation, use simpler patterns or switch to explicit validation:
// Instead of complex regex constraint
e.GET("/user/:id", func(c echo.Context) error {
id := c.Param("id")
if !isValidUserID(id) {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user ID")
}
return c.JSON(http.StatusOK, map[string]string{"id": id})
})
Implement rate limiting to mitigate the impact of potential ReDoS attacks:
import "github.com/ulule/limiter/v7"
rateLimitMiddleware := limiter.NewMiddleware(
limiter.NewRate("10-M") // 10 requests per minute
)
e.Use(rateLimitMiddleware)
For JSON body validation, use struct tags with safer validation libraries:
import "github.com/go-playground/validator/v10"
type User struct {
Email string `json:"email" validate:"email"`
Password string `json:"password" validate:"min=8,max=72"`
}
func validateStruct(user *User) error {
v := validator.New()
return v.Struct(user)
}
Consider using finite state machines or specialized parsers for complex input validation instead of regex:
// Simple state machine for specific validation
func validateComplexInput(input string) bool {
state := 0
for _, char := range input {
switch state {
case 0:
if char == 'a' { state = 1 } else { return false }
case 1:
if char == 'b' { state = 2 } else if char == 'a' { state = 1 } else { return false }
case 2:
if char == 'c' { state = 3 } else if char == 'a' { state = 1 } else { return false }
case 3:
return false // No more characters allowed
}
}
return state == 3
}
Finally, implement comprehensive monitoring and alerting for regex-related performance issues in production:
func monitorRegexPerformance(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
start := time.Now()
err := next(c)
duration := time.Since(start)
// Track slow regex operations
if duration > 100*time.Millisecond {
log.Printf("Potential regex issue: %s %s took %v", c.Request().Method, c.Path(), duration)
// Send alert to monitoring system
}
return err
}
}
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |