HIGH rate limiting bypassfiber

Rate Limiting Bypass in Fiber

How Rate Limiting Bypass Manifests in Fiber

Rate limiting bypass in Fiber applications typically occurs when the rate limiting mechanism can be circumvented through client manipulation or implementation flaws. In Go applications using Fiber, the most common bypass vectors include header manipulation, IP spoofing, and improper key generation for rate limiting calculations.

A classic bypass pattern involves manipulating the X-Forwarded-For header. When Fiber applications run behind a reverse proxy or load balancer, they often rely on this header to identify the client IP. Attackers can simply add multiple IP addresses to this header, causing the application to read the wrong IP for rate limiting purposes:

GET /api/endpoint HTTP/1.1
Host: example.com
X-Forwarded-For: 1.2.3.4, 5.6.7.8, 9.10.11.12

In this scenario, the application might read 9.10.11.12 as the client IP, allowing the attacker to distribute requests across multiple apparent IPs. This is particularly effective when the rate limiting is implemented per-IP without validating the header's authenticity.

Another common Fiber-specific bypass involves improper token bucket implementation. Consider this vulnerable pattern:

store := redis.NewClient(&redis.Options{Addr: "localhost:6379"})

app.Use(rate.New(rate.Config{
    Store:          store,
    Filter:         nil,
    TokenBucket: &rate.TokenBucket{
        FillInterval: time.Second,
        Capacity:     10,
        Quantum:      1,
    },
    MaxRetries:     5,
    Expiration:     0,
}))

The vulnerability here is that the default IP filter doesn't validate proxy headers. An attacker can bypass this by sending requests through different network paths or manipulating headers that affect how the client IP is determined.

Timing-based bypasses also occur in Fiber applications. When rate limiting is implemented with in-memory storage in development but switches to Redis in production, the behavior changes dramatically. An attacker who discovers this can exploit the different implementations:

// Vulnerable: in-memory store resets on restart
store := memory.New()

versus:

// Production: distributed store
store := redis.NewClient(&redis.Options{Addr: "redis:6379"})

API endpoint structure can also create bypass opportunities. When different endpoints have different rate limits but share the same underlying resource, attackers can rotate through endpoints to distribute their request load:

/api/v1/users (10 req/min)
/api/v2/users (100 req/min)
/api/private/users (unlimited)

Finally, Fiber applications often mishandle concurrent requests to the same endpoint. Without proper atomic operations in the rate limiting store, race conditions can allow multiple requests to succeed simultaneously, effectively bypassing the limit:

// Vulnerable: non-atomic check-and-decrement
if store.Get(key) > 0 {
    store.Decr(key)
    // Process request
} else {
    // Rate limit exceeded
}

This creates a window where multiple requests can pass the check before any are decremented, allowing brief bursts that exceed the intended limit.

Fiber-Specific Detection

Detecting rate limiting bypasses in Fiber applications requires both manual testing and automated scanning. The middleBrick scanner excels at identifying these specific vulnerabilities through its comprehensive black-box testing approach.

For manual detection, start by examining how your Fiber application determines client identity. Look for patterns like:

clientIP := c.IP()
// vs
clientIP := c.Locals("ip") // set by middleware
// vs
clientIP := c.Get("X-Forwarded-For") // vulnerable if not validated

Test header manipulation by sending requests with various X-Forwarded-For values and observing whether the rate limit changes. A secure implementation should either reject requests with multiple IPs or validate that the header came from a trusted proxy.

Monitor your rate limiting store during testing. With Redis backend, watch for these indicators of bypass:

redis> MONITOR
1234567890.123456 [0 127.0.0.1:54321] "GET" "rate:192.168.1.1"
1234567890.123500 [0 127.0.0.1:54321] "GET" "rate:10.0.0.1"

If you see multiple different IPs being checked for what should be a single client, you may have a bypass vulnerability.

middleBrick's automated scanning specifically tests for rate limiting bypass by:

  • Testing header manipulation patterns across 12 different header variations
  • Simulating distributed attacks from multiple apparent sources
  • Measuring actual request throughput versus expected limits
  • Identifying inconsistent rate limiting across similar endpoints

The scanner reports findings with severity levels and provides specific remediation guidance. For example, it might detect that your /login endpoint allows 100x more requests than intended due to improper IP tracking.

Implement monitoring to detect bypass attempts in production. Track metrics like:

rate_limit_bypass_attempts_total{endpoint="api/login"}
rate_limit_bypass_successful_total{endpoint="api/login"}

These metrics help identify when attackers are actively attempting to circumvent your rate limiting.

Fiber-Specific Remediation

Securing rate limiting in Fiber applications requires implementing robust client identification and atomic operations. Here's how to fix common vulnerabilities:

First, implement trusted proxy configuration to prevent header manipulation:

app := fiber.New(fiber.Config{
    Prefork:       false,
    TrustedProxies: []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
})

// Use c.IP() which respects TrustedProxies
app.Use(rate.New(rate.Config{
    Store: redis.NewClient(&redis.Options{Addr: "redis:6379"}),
    Filter: &rate.IPFilter{}, // respects trusted proxies
    TokenBucket: &rate.TokenBucket{
        FillInterval: time.Second,
        Capacity:     100,
        Quantum:      1,
    },
}))

This ensures that X-Forwarded-For headers are only trusted from specified proxy IP ranges, preventing external manipulation.

For atomic rate limiting operations, use Redis transactions or Lua scripts:

store := redis.NewClient(&redis.Options{Addr: "redis:6379"})

// Atomic check-and-decrement using Lua
luaScript := `local current = redis.call("GET", KEYS[1])
if current < tonumber(ARGV[1]) then
    redis.call("INCRBY", KEYS[1], -1)
    redis.call("EXPIRE", KEYS[1], tonumber(ARGV[2]))
    return 1
else
    return 0
end`

app.Use(func(c *fiber.Ctx) error {
    clientIP := c.IP()
    key := fmt.Sprintf("rate:%s:%s", clientIP, c.Path())
    
    result, err := store.Eval(luaScript, []string{key}, []string{"1", "60"}).Result()
    if err != nil || result == int64(0) {
        return c.Status(fiber.StatusTooManyRequests).SendString("Rate limit exceeded")
    }
    return c.Next()
})

This prevents race conditions where multiple requests could pass the rate limit check simultaneously.

Implement consistent rate limiting across your entire API surface:

type rateLimiter struct {
    store *redis.Client
    limits map[string]int
}

func (rl *rateLimiter) limitByEndpoint(c *fiber.Ctx, max int) error {
    clientIP := c.IP()
    endpoint := c.Path()
    key := fmt.Sprintf("rate:%s:%s", clientIP, endpoint)
    
    current, err := rl.store.Incr(key).Result()
    if err != nil {
        return err
    }
    if current == 1 {
        rl.store.Expire(key, time.Minute)
    }
    if int(current) > max {
        return fiber.ErrTooManyRequests
    }
    return nil
}

// Apply consistent limits
app.Use(func(c *fiber.Ctx) error {
    switch c.Path() {
    case "/api/login":
        return (&rateLimiter{limits: map[string]int{"/api/login": 10}}).limitByEndpoint(c, 10)
    case "/api/data":
        return (&rateLimiter{limits: map[string]int{"/api/data": 100}}).limitByEndpoint(c, 100)
    default:
        return c.Next()
    }
})

Add monitoring and alerting for rate limiting anomalies:

app.Use(func(c *fiber.Ctx) error {
    start := time.Now()
    err := c.Next()
    if err != nil {
        if err == fiber.ErrTooManyRequests {
            // Track rate limit violations
            metrics.RateLimitViolations.With(prometheus.Labels{
                "endpoint": c.Path(),
                "client_ip": c.IP(),
            }).Inc()
        }
        return err
    }
    return nil
})

Finally, test your implementation thoroughly by simulating bypass attempts. Use tools like curl or automated scripts to verify that header manipulation, IP rotation, and concurrent requests cannot exceed your intended limits.

Related CWEs: resourceConsumption

CWE IDNameSeverity
CWE-400Uncontrolled Resource Consumption HIGH
CWE-770Allocation of Resources Without Limits MEDIUM
CWE-799Improper Control of Interaction Frequency MEDIUM
CWE-835Infinite Loop HIGH
CWE-1050Excessive Platform Resource Consumption MEDIUM

Frequently Asked Questions

How can I tell if my Fiber application is vulnerable to rate limiting bypass?
Test by sending requests with manipulated X-Forwarded-For headers containing multiple IPs. If your rate limit changes based on header content, you're vulnerable. Also check if different endpoints with similar functionality have inconsistent rate limits, as attackers can rotate through them to bypass restrictions.
Does middleBrick scan for rate limiting bypass vulnerabilities in Fiber applications?
Yes, middleBrick's black-box scanner specifically tests for rate limiting bypass by manipulating headers, simulating distributed attacks, and measuring actual throughput versus expected limits. It identifies vulnerabilities like improper IP tracking, inconsistent endpoint limits, and race condition opportunities in your Fiber API.