Rate-Limiting Strategy in DeskcommCRM: Fixed-Window Protection with Redis

DeskcommCRM employs a fixed-window rate-limiting strategy using Redis counters to protect authentication endpoints, applying separate IP-based and identifier-based limits to prevent brute-force attacks.

DeskcommCRM implements a robust rate-limiting strategy to safeguard its authentication surface against abuse and distributed attacks. The system relies on Redis-backed counters managed through Upstash, with core logic residing in lib/auth/rate-limit.ts. This approach utilizes a fixed-window algorithm with dual-dimensional throttling to balance security and user experience.

How the Fixed-Window Rate Limiter Works

The implementation leverages a fixed-window algorithm rather than a sliding window, providing burst-tolerant protection that resets after configurable time intervals. Each authentication attempt increments a counter in Redis using atomic INCR and EXPIRE operations, ensuring accurate tracking even under concurrent load.

Two-Dimensional Bucket Strategy

The rate-limiting strategy applies two-dimensional limits that operate independently:

  • Per-IP buckets isolate traffic from single sources, preventing individual networks from overwhelming the system.
  • Per-identifier buckets throttle attempts against specific accounts (emails or tokens), protecting against distributed brute-force attacks that rotate IP addresses.

This dual approach ensures that an attacker cannot bypass limits simply by switching networks or targeting multiple accounts from a single location.

Privacy-Preserving Key Hashing

All IP addresses and identifiers are hashed using sha256 before storage in Redis. This key construction method keeps bucket keys opaque, preventing the leakage of raw client data while maintaining consistent rate-limit tracking. The hashing occurs in lib/auth/rate-limit.ts before any Redis operations.

Graceful Fallback for Missing IPs

When client IP addresses cannot be determined (null), the system skips IP-based limits rather than applying a global bucket. This fallback handling prevents a single misconfigured proxy from triggering a denial-of-service lockout for the entire installation. Requests without IPs remain subject to identifier-based limits, maintaining partial protection.

Environment-Based Configuration

Default limits are exported in the AUTH_LIMITS constant (lines [136-146] of lib/auth/rate-limit.ts). Administrators can override these values through environment variables such as AUTH_RATE_LIMIT_LOGIN_IP. Invalid configurations automatically fall back to production defaults, ensuring the system remains protected even with misconfiguration.

Actions Covered by Rate Limiting

The authRateLimited function (lines [64-100]) enforces specific limits for five distinct authentication actions defined in the AUTH_LIMITS object.

Login Protection

The login action applies the strictest controls: 60 attempts per 5 minutes per IP and 5 attempts per 5 minutes per account. This dual limit blocks both single-source brute-force attacks and distributed attempts against high-value accounts. Failed attempts trigger registrarFalhaDeLogin to increment the per-identifier counter.

Signup Throttling

Account creation is limited to 20 attempts per hour per IP through the signup action. This prevents mass account registration while allowing legitimate team growth. Unlike login, signup typically applies only IP-based limits since the account identifier does not yet exist.

Password Reset Security

The reset action restricts password recovery to 30 attempts per hour per IP and 3 attempts per hour per account. These tight limits prevent automated enumeration and mass-reset attacks while providing legitimate users sufficient retry capacity.

Invitation and Organization Recovery

Two specialized flows receive dedicated protection:

  • invite_accept: Limited to 60 attempts per hour per IP, throttling acceptance of invitation tokens without restricting legitimate team onboarding.
  • org_recovery: Highly restricted to 5 attempts per hour per IP and 3 attempts per hour per account, protecting the first-access recovery flow that creates new organizations.

Implementation Code Examples

The rate limiter integrates into authentication flows through the authRateLimited helper. Below is the pattern used to protect login endpoints in DeskcommCRM:

import { authRateLimited, AUTH_LIMITS } from "@/lib/auth/rate-limit";
import { contaBloqueadaPorFalhas, registrarFalhaDeLogin } from "@/lib/auth/rate-limit";

async function handleLogin(email: string, password: string) {
  // Check both IP and identifier buckets before processing
  if (await authRateLimited("login", email, AUTH_LIMITS.login)) {
    return { error: "Muitas tentativas – aguarde e tente novamente." };
  }

  const valid = await verifyPassword(email, password);
  if (!valid) {
    // Record failure for per-account tracking
    await registrarFalhaDeLogin(email, AUTH_LIMITS.login);
    if (await contaBloqueadaPorFalhas(email, AUTH_LIMITS.login)) {
      return { error: "Conta temporariamente bloqueada por falhas." };
    }
    return { error: "Credenciais inválidas." };
  }

  return { success: true };
}

For signup endpoints, the implementation passes null as the identifier since the account does not yet exist:

async function handleSignup(email: string) {
  if (await authRateLimited("signup", null, AUTH_LIMITS.signup)) {
    return { error: "Muitas tentativas de cadastro – aguarde." };
  }
  // Account creation logic follows...
}

Reusable Infrastructure Across the Platform

Beyond authentication, the underlying checkRateLimit function from lib/ai/dispatcher/rate-limit.ts serves as the generic engine for webhook capture and the AI dispatcher. This shared infrastructure ensures consistent throttling semantics across all resource-intensive operations in DeskcommCRM.

Summary

  • DeskcommCRM implements a fixed-window rate-limiting strategy using Redis (Upstash) with atomic INCR and EXPIRE operations.
  • Two-dimensional limits track both per-IP and per-identifier (email/token) buckets to prevent distributed attacks.
  • Keys are hashed with sha256 before storage to protect client privacy.
  • The system covers five authentication actions—login, signup, reset, invite_accept, and org_recovery—with specific thresholds for each.
  • Missing IP addresses trigger fallback handling that skips IP limits rather than applying global restrictions.
  • Configuration occurs through the AUTH_LIMITS constant with environment variable overrides.

Frequently Asked Questions

What type of rate-limiting algorithm does DeskcommCRM use?

DeskcommCRM uses a fixed-window rate-limiting algorithm implemented in lib/auth/rate-limit.ts. This approach increments a single counter for each time window rather than tracking sliding time boundaries, providing burst-tolerant protection that expires after a configurable number of seconds (windowSec).

How does DeskcommCRM prevent rate-limit keys from leaking sensitive data?

The system hashes all IP addresses and identifiers using sha256 before constructing Redis keys. This ensures that raw client data never appears in the keyspace, maintaining privacy while allowing consistent rate tracking across the fixed windows defined in AUTH_LIMITS.

Can administrators customize the rate limits without modifying code?

Yes. While default values are hardcoded in the AUTH_LIMITS constant (lines [136-146]), administrators can override specific limits through environment variables such as AUTH_RATE_LIMIT_LOGIN_IP. Invalid values automatically fall back to production defaults to prevent accidental unprotected states.

What happens if the system cannot determine the client's IP address?

When IP detection returns null, the rate limiter applies fallback handling by skipping the IP-based bucket entirely. The request remains subject to identifier-based limits (if applicable), preventing a global DoS condition that would lock out all users due to a single misconfigured proxy or network condition.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →