RepoPilotOpen in app →

rack/rack-attack

Rack middleware for blocking & throttling

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 5w ago
  • 25+ active contributors
  • Distributed ownership (top contributor 39% of recent commits)
Show 3 more →
  • MIT licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/rack/rack-attack)](https://repopilot.app/r/rack/rack-attack)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/rack/rack-attack on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: rack/rack-attack

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/rack/rack-attack shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 5w ago
  • 25+ active contributors
  • Distributed ownership (top contributor 39% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live rack/rack-attack repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/rack/rack-attack.

What it runs against: a local clone of rack/rack-attack — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in rack/rack-attack | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 64 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>rack/rack-attack</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rack/rack-attack. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/rack/rack-attack.git
#   cd rack-attack
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of rack/rack-attack and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rack/rack-attack(\\.git)?\\b" \\
  && ok "origin remote is rack/rack-attack" \\
  || miss "origin remote is not rack/rack-attack (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "lib/rack/attack.rb" \\
  && ok "lib/rack/attack.rb" \\
  || miss "missing critical file: lib/rack/attack.rb"
test -f "lib/rack/attack/check.rb" \\
  && ok "lib/rack/attack/check.rb" \\
  || miss "missing critical file: lib/rack/attack/check.rb"
test -f "lib/rack/attack/request.rb" \\
  && ok "lib/rack/attack/request.rb" \\
  || miss "missing critical file: lib/rack/attack/request.rb"
test -f "lib/rack/attack/cache.rb" \\
  && ok "lib/rack/attack/cache.rb" \\
  || miss "missing critical file: lib/rack/attack/cache.rb"
test -f "lib/rack/attack/configuration.rb" \\
  && ok "lib/rack/attack/configuration.rb" \\
  || miss "missing critical file: lib/rack/attack/configuration.rb"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 64 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~34d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/rack/rack-attack"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Rack::Attack is Rack middleware that protects Rails and Rack applications from abusive clients by enabling fine-grained control over when to allow, block, and throttle requests based on request properties. It uses in-memory or distributed caches (Redis, Memcached, Rails cache stores) to track request patterns and enforce rate limits, IP-based blocklists/safelists, and dynamic fail2ban/allow2ban banning strategies. Monolithic gem structure: lib/rack/attack.rb is the main entry point, with modular components under lib/rack/attack/ including checks (safelist.rb, blocklist.rb), throttling (throttle.rb), banning strategies (fail2ban.rb, allow2ban.rb), and pluggable store proxies (store_proxy/ directory supporting Redis, Memcached, Rails cache stores). Configuration lives in lib/rack/attack/configuration.rb, with examples in examples/ and docs in docs/.

👥Who it's for

Rails and Rack application developers who need production-grade DDoS protection, API rate limiting, and abuse prevention without external third-party services. Specifically DevOps engineers, API maintainers, and security-conscious web framework users who want middleware-level request filtering.

🌱Maturity & risk

Highly mature and production-ready. The project has a stable v6 release branch (6-stable), comprehensive CI via GitHub Actions (build.yml), extensive test coverage, and active maintenance with support for 8+ Rails versions and 5+ Redis versions. Last activity visible in Appraisals and gemfiles indicates recent updates.

Low risk. Single-maintainer dependency is possible but mitigated by strong test suite, stable API, and wide adoption in production Rails apps. The project maintains compatibility across many cache backends (Redis, Memcached, Rails 7-8, Dalli 3+) which adds complexity but is well-managed via appraisals. No obvious security vulnerabilities based on structure, though cache store selection can impact performance.

Active areas of work

Active development on multi-version compatibility: gemfiles/ contains appraisals for Rails 7.0-8.1 and Redis 4-5, indicating ongoing testing across dependency versions. The branch in README says viewers are on development branch with unreleased features. No specific milestones visible, but the structure shows continuous effort to maintain compatibility.

🚀Get running

git clone https://github.com/rack/rack-attack.git
cd rack-attack
bundle install
bundle exec rake test

Daily commands:

bundle exec rake test                          # Run full test suite
bundle exec rubocop                            # Check style compliance
rake appraisal:install                        # Install all gemfile variants
rake appraisal:test                           # Test against all dependency versions

🗺️Map of the codebase

  • lib/rack/attack.rb — Main entry point and middleware orchestrator that initializes all checks, handles request filtering, and coordinates the entire blocking/throttling pipeline.
  • lib/rack/attack/check.rb — Abstract base class for all check types (blocklist, safelist, throttle, track); defines the interface and lifecycle every rule must implement.
  • lib/rack/attack/request.rb — Extended Rack request wrapper that provides convenient accessors for IP, path, and custom properties used throughout rule matching.
  • lib/rack/attack/cache.rb — Unified cache abstraction layer managing backend stores (Redis, Memcached, etc.) for throttle counters and fail2ban/allow2ban state.
  • lib/rack/attack/configuration.rb — Configuration DSL parser and validator; processes block-based rule definitions and manages global settings for the middleware.
  • lib/rack/attack/throttle.rb — Rate-limiting rule implementation with per-key counters; drives the core throttling behavior and response logic.
  • lib/rack/attack/fail2ban.rb — Automatic IP banning via counter threshold; escalates throttles into blocks after repeated violations within a time window.

🛠️How to make changes

Add a new blocklist rule

  1. In your configuration file or initializer, call Rack::Attack.blocklist() with a name and block returning truthy for requests to block (examples/rack_attack.rb)
  2. The block receives a Rack::Attack::Request and should use properties like request.ip, request.path, or custom accessors (lib/rack/attack/request.rb)
  3. Blocked requests are immediately halted; configure a custom response via Rack::Attack.blocklist_response if needed (lib/rack/attack.rb)

Add a new throttle rule with rate limits

  1. Call Rack::Attack.throttle() with a name, limit, period, and discriminator block (examples/rack_attack.rb)
  2. The discriminator block returns a unique key (e.g., IP, user_id); Rack::Attack increments a counter per key in cache (lib/rack/attack/throttle.rb)
  3. When count exceeds limit within the period, requests are throttled; customize the response with Rack::Attack.throttled_response (lib/rack/attack.rb)
  4. Cache backend defaults to in-memory; configure Redis or Memcached via Rack::Attack.cache.store = (lib/rack/attack/cache.rb)

Integrate Fail2Ban for auto-escalation

  1. Define a throttle rule as normal (e.g., limit per IP per endpoint) (examples/rack_attack.rb)
  2. Separately, call Rack::Attack.fail2ban() specifying the same discriminator, a failure threshold, and ban duration (lib/rack/attack/fail2ban.rb)
  3. Fail2Ban monitors throttle hits; when threshold is crossed, it adds the key to a hard blocklist automatically (lib/rack/attack.rb)
  4. Optionally define a safelist to exempt trusted IPs from Fail2Ban escalation (lib/rack/attack/safelist.rb)

Add a custom cache store backend

  1. Create a new proxy class in lib/rack/attack/store_proxy/ inheriting from BaseProxy (lib/rack/attack/base_proxy.rb)
  2. Implement #increment and #read methods to wrap your store's API (e.g., Redis INCR, GET) (lib/rack/attack/store_proxy/redis_proxy.rb)
  3. Register the proxy in the cache initialization logic so it's auto-detected, or manually set Rack::Attack.cache.store = YourProxy.new(client) (lib/rack/attack/cache.rb)

🔧Why these technologies

  • Rack Middleware — Provides standard, language-agnostic interface for HTTP filtering; integrates seamlessly with Rails and any Rack-based framework without code changes
  • Pluggable Cache Backends (Redis, Memcached, ActiveSupport) — Distributed rate-limiting counters and ban state must be shared across processes; supports production deployments at scale and development-friendly in-memory stores
  • Time-window based Throttling — Simple, predictable rate-limiting model; avoids leaky bucket complexity while providing intuitive per-second/per-minute limits
  • Fail2Ban Escalation Pattern — Automatic adaptive blocking: punishes repeated attackers without manual intervention; threshold-based to avoid false positives from temporary spikes

⚖️Trade-offs already made

  • Single-process in-memory cache as default

    • Why: Zero dependencies; easy setup for development and small deployments
    • Consequence: Not suitable for multi-process or distributed deployments; counters reset on process restart
  • Per-discriminator (IP, user_id, etc.) counters rather than per-route buckets

    • Why: Simpler, more flexible rule configuration; natural match to real-world threat models
    • Consequence: Cannot easily express per-user-per-endpoint limits without custom code; requires multiple throttle rules
  • Fail2Ban as separate explicit rule, not automatic on throttle

    • Why: Gives operators explicit control over escalation; avoids accidental auto-bans from misconfigured throttles
    • Consequence: Requires additional configuration; users must remember to pair throttles with fail2ban for auto-escalation
  • Synchronous cache increment/read in request path

    • Why: Guarantees accurate counters; no queueing latency or eventual consistency issues
    • Consequence: Request latency bound by cache latency (5ms+ for Redis over network

🪤Traps & gotchas

  1. Cache store initialization: Must configure Rack::Attack.cache.store = before middleware processes requests, or use Rails cache auto-detection (requires Rails). 2. Redis connection requirements: Redis/Memcached must be running for throttle state; without it, middleware fails open (allows traffic) by default. 3. IP detection: Request IP detection depends on header configuration (X-Forwarded-For, CF-Connecting-IP); must align with reverse proxy setup. 4. Thread safety: Cache store proxies must be thread-safe; some (like plain Redis) may need connection pooling. 5. Rack vs Rails: Middleware works with bare Rack but Rails Railtie (lib/rack/attack/railtie.rb) auto-inserts it; avoid double-insertion if manually adding.

🏗️Architecture

💡Concepts to learn

  • Token Bucket Rate Limiting — Core algorithm in throttle.rb; understanding how tokens refill per period and are consumed per request is critical to configuring effective rate limits
  • Fail2Ban / Allow2Ban Dynamic Banning — Rack::Attack's fail2ban.rb and allow2ban.rb implement automatic escalating bans based on request patterns; understanding the state machine (strikes, bans, resets) is key to preventing false positives
  • IP Subnet Matching (CIDR Notation) — Safelists and blocklists use CIDR subnets (e.g., 192.168.0.0/16); understanding IP masking and range checking prevents misconfiguration of network-level rules
  • Distributed Cache Coherency — When using Redis/Memcached backends, throttle counts and ban state are shared across multiple app processes; cache store selection impacts correctness of rate limits under load
  • Rack Middleware Execution Order — Rack::Attack must run early in middleware stack to block before app code executes; placement relative to Rails middleware (auth, logging) affects rule matching and performance
  • Proxy Header Trust (X-Forwarded-For) — Real client IP detection relies on reverse proxy headers; misconfigured header trust can lead to blocking wrong clients or spoofing by attackers
  • Store Proxy Adapter Pattern — Rack::Attack abstracts cache backends via pluggable proxies (Redis, Memcached, Rails cache); understanding how store_proxy/ adapts different backend APIs to common interface is key to extending backends
  • redis/redis-rb — Official Redis Ruby client; required for Redis-backed cache store in Rack::Attack
  • memcached/memcached — Memcached protocol server; alternative distributed cache backend supported via Dalli adapter
  • rails/rails — Rack::Attack ships with Railtie for Rails integration and uses Rails cache store adapters
  • kickstarter/rack-ssl-enforcer — Complementary Rack middleware for HTTPS enforcement; often used alongside Rack::Attack for security
  • jordansissel/fpm — Not a direct relationship, but fail2ban and allow2ban strategies in Rack::Attack are inspired by Linux fail2ban tool concepts

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for all store_proxy implementations

The repo supports multiple cache backends (Redis, Memcached, ActiveSupport::Cache) via store_proxy classes, but spec/acceptance lacks targeted tests for each proxy type. Currently cache_store_config_*_spec.rb files exist but they test high-level behavior. Missing are specific unit tests for each store_proxy implementation (RedisProxy, DalliProxy, MemCacheStoreProxy, RedisCacheStoreProxy, RedisStoreProxy) covering edge cases like connection failures, serialization, TTL handling, and concurrent access patterns.

  • [ ] Create spec/unit/rack/attack/store_proxy/ directory structure
  • [ ] Add spec/unit/rack/attack/store_proxy/redis_proxy_spec.rb with tests for get/set/delete operations
  • [ ] Add spec/unit/rack/attack/store_proxy/dalli_proxy_spec.rb covering Memcached-specific behavior
  • [ ] Add spec/unit/rack/attack/store_proxy/redis_cache_store_proxy_spec.rb and other cache store variants
  • [ ] Test error handling when backend is unavailable
  • [ ] Test TTL and expiration behavior across all proxies

Add comprehensive documentation for PathNormalizer and Request customization

The codebase includes lib/rack/attack/path_normalizer.rb and lib/rack/attack/request.rb which enable powerful request filtering and path-based throttling, but docs/advanced_configuration.md doesn't cover these features. spec/acceptance/extending_request_object_spec.rb exists showing usage patterns, but users lack clear guidance on when and how to use these features.

  • [ ] Create docs/request_customization.md documenting lib/rack/attack/request.rb
  • [ ] Document lib/rack/attack/path_normalizer.rb with real-world examples (e.g., normalizing API versioning, query parameter ordering)
  • [ ] Add examples to docs/ showing how to extend Rack::Attack::Request for custom matching logic
  • [ ] Include performance considerations for custom request properties
  • [ ] Reference existing spec/acceptance/extending_request_object_spec.rb patterns in documentation

Add support matrix and CI workflow for newer Ruby/Rails/Rack versions

The gemfiles/ directory shows extensive version testing setup (Rails 8.1, Ruby 3.x support expected), but .github/workflows/build.yml doesn't explicitly document which Ruby/Rails/Rack version combinations are officially tested. The Appraisals file suggests multi-version testing is configured but CI output doesn't clearly show a support matrix. Adding explicit version compatibility tests and documentation would help contributors understand what they need to test.

  • [ ] Add explicit Ruby version matrix to .github/workflows/build.yml (e.g., 3.1, 3.2, 3.3, 3.4)
  • [ ] Update .github/workflows/build.yml to test with multiple Rack versions explicitly (rack_2.gemfile, rack_3.gemfile)
  • [ ] Create docs/compatibility_matrix.md documenting officially tested combinations
  • [ ] Add Ruby version requirement check to rack-attack.gemspec if not already present
  • [ ] Add CI workflow that runs bundler with each gemfile/ configuration and reports results

🌿Good first issues

  • Add integration tests for lib/rack/attack/path_normalizer.rb: File exists but is not clearly tested in visible test structure. Normalize path handling for routes with query strings or fragments.
  • Expand example configurations in examples/rack_attack.rb: Add real-world patterns like tiered throttling (different limits for authenticated vs guest users), API endpoint-specific rules, and webhook signature validation examples.
  • Document cache store proxy behavior: Add troubleshooting guide in docs/ explaining what happens when Redis/Memcached is down, fallback modes, and performance characteristics of each store_proxy adapter.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 728d610 — Eagerly check for store validity (#714) (byroot)
  • 6c16764 — Test against Ruby 4.0 (#715) (byroot)
  • e938879 — Upgrade rubocop (#710) (santib)
  • d1a979d — Remove unnecessary pooled specs (#708) (santib)
  • 77195a5 — lowercase header key on README responder example for Rack 3 compatibility (#705) (r-plus)
  • 1155c26 — ci: test against a compatible connection_pool version (#706) (santib)
  • 4a021df — Inherit Request class from ActionDispatch if available (bdewater-thatch)
  • b2ebab9 — build(deps): bump actions/checkout from 5 to 6 (#702) (dependabot[bot])
  • 676ba26 — ci: updates ruby versions (grzuy)
  • 6a9209f — ci: updates rails versions (grzuy)

🔒Security observations

Rack::Attack is a mature security middleware project with a well-organized codebase. No critical vulnerabilities were identified from the static file structure analysis. Primary concerns are around dependency version management across multiple supported versions and potential cache backend configuration risks. The project lacks explicit security best practices documentation but otherwise demonstrates good architectural separation of concerns with dedicated modules for different protection mechanisms (blocklist, safelist, throttle, fail2ban, allow2ban). Recommended actions include enabling automated dependency vulnerability scanning, documenting secure configuration for supported cache backends, and adding security best practices guidelines.

  • Medium · Dependency Version Management Risk — gemfiles/ directory (multiple gemfiles). The codebase supports multiple versions of dependencies (Rails 7.0-8.1, Redis 4-5, Active Support 7.0-8.1, etc.) through Appraisals gemfiles. While this enables broad compatibility testing, it increases the attack surface if older dependency versions contain known vulnerabilities. The gemfiles directory shows support for potentially outdated versions that may have unpatched security issues. Fix: Implement a dependency vulnerability scanner in CI/CD (e.g., Dependabot, Snyk). Set minimum version requirements for dependencies with known CVEs. Consider deprecating support for versions older than 2 years. Review .github/dependabot.yml configuration to ensure automated security updates are enabled.
  • Medium · Potential Cache Backend Security Issues — lib/rack/attack/store_proxy/ directory and lib/rack/attack/cache.rb. The codebase supports multiple cache backends (Redis, Dalli/Memcached, Active Support cache stores) through store proxy implementations. Different backends may have varying security properties (e.g., Memcached lacks authentication by default, Redis may be exposed). Improper configuration could expose the cache store to unauthorized access. Fix: Document security requirements for each cache backend. Recommend TLS/SSL for Redis, proper authentication configuration, and network isolation. Provide configuration examples with security best practices. Add validation warnings when insecure defaults are detected.
  • Low · Missing Security Headers Documentation — README.md and docs/. While Rack::Attack handles request blocking and throttling, the README and documentation do not explicitly document the security headers being set or recommended additional security middleware to work in conjunction. Fix: Add a security best practices section documenting recommended complementary security headers and middleware. Include configuration examples for common security scenarios (e.g., rate limiting API endpoints, blocking known malicious IPs).
  • Low · No Evidence of Input Validation on Request Parameters — lib/rack/attack/request.rb and lib/rack/attack/path_normalizer.rb. The codebase contains a custom Request object (lib/rack/attack/request.rb) and path normalizer (lib/rack/attack/path_normalizer.rb). Without visible input validation implementation, there could be edge cases where specially crafted requests bypass protection mechanisms. Fix: Review path normalization logic for bypasses (e.g., double URL encoding, Unicode normalization). Add tests for edge cases. Document any known limitations in path matching and wildcard handling.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · rack/rack-attack — RepoPilot