New Issue Checklist
- This is not a security vulnerability; it is a rate-limit isolation bug.
- I searched the existing issues but did not find this behavior reported.
Issue Description
When configuring more than one rateLimit rule with redisUrl, rate-limit state is not scoped to the configured route, nor to the individual rule/window.
Steps to reproduce
Configure two rules with the same Redis instance:
rateLimit: [
{
requestPath: '/functions/a',
requestMethods: ['POST'],
requestTimeWindow: 30 * 24 * 60 * 60 * 1000,
requestCount: 10,
zone: 'user',
redisUrl: 'redis://localhost:6379'
},
{
requestPath: '/functions/b',
requestMethods: ['POST'],
requestTimeWindow: 60 * 60 * 1000,
requestCount: 5,
zone: 'user',
redisUrl: 'redis://localhost:6379'
}
]
For the same authenticated user:
- Call
POST /functions/a. This creates Redis key rl:<userId> with a 30-day TTL.
- Call
POST /functions/b. It increments that same key despite using a different path and rate-limit rule.
- The second rule applies its
max: 5 to the shared hit count, while retaining the 30-day TTL.
Reverse the order and the shared key expires after one hour instead.
Actual Outcome
requestPath is used only to select the middleware. The key generator returns only the app ID, session token, user ID, or IP address.
With Redis, each RedisStore is constructed without a prefix, so rate-limit-redis uses its default rl: prefix for every configured rule. Different endpoints therefore share rl:<userId>.
This also means that rules with different windowMs values share a TTL. rate-limit-redis sets the TTL only when the key is first created (unless expiry reset is enabled), so the effective window depends on which endpoint is called first. Multiple limits for the same endpoint cannot be composed safely either.
Expected Outcome
Each independent rate-limit rule should use its own Redis key namespace. At a minimum, Redis keys should be scoped by requestPath, method, and zone. To safely support multiple limits on the same endpoint, the namespace should also distinguish the configured window and count (or Parse Server should expose a rule identifier).
One possible fix would be to pass a deterministic prefix to RedisStore based on the rule identity, for example a compact hash of:
{ requestPath, requestMethods, zone, requestTimeWindow, requestCount }
followed by the existing user/session/IP key.
Environment
- Parse Server version:
9.9.0 (HULAB fork based on Parse Server 9.9.0)
- Operating system: Amazon Linux 2023
- Local or remote host: AWS Elastic Beanstalk
- Database: MongoDB (not involved)
- Client SDK: not involved; reproducible with HTTP requests
Logs
No server error is emitted. The collision is visible directly in Redis as the same rl:<userId> key being incremented by both routes.
New Issue Checklist
Issue Description
When configuring more than one
rateLimitrule withredisUrl, rate-limit state is not scoped to the configured route, nor to the individual rule/window.Steps to reproduce
Configure two rules with the same Redis instance:
For the same authenticated user:
POST /functions/a. This creates Redis keyrl:<userId>with a 30-day TTL.POST /functions/b. It increments that same key despite using a different path and rate-limit rule.max: 5to the shared hit count, while retaining the 30-day TTL.Reverse the order and the shared key expires after one hour instead.
Actual Outcome
requestPathis used only to select the middleware. The key generator returns only the app ID, session token, user ID, or IP address.With Redis, each
RedisStoreis constructed without aprefix, sorate-limit-redisuses its defaultrl:prefix for every configured rule. Different endpoints therefore sharerl:<userId>.This also means that rules with different
windowMsvalues share a TTL.rate-limit-redissets the TTL only when the key is first created (unless expiry reset is enabled), so the effective window depends on which endpoint is called first. Multiple limits for the same endpoint cannot be composed safely either.Expected Outcome
Each independent rate-limit rule should use its own Redis key namespace. At a minimum, Redis keys should be scoped by
requestPath, method, and zone. To safely support multiple limits on the same endpoint, the namespace should also distinguish the configured window and count (or Parse Server should expose a rule identifier).One possible fix would be to pass a deterministic
prefixtoRedisStorebased on the rule identity, for example a compact hash of:followed by the existing user/session/IP key.
Environment
9.9.0(HULAB fork based on Parse Server 9.9.0)Logs
No server error is emitted. The collision is visible directly in Redis as the same
rl:<userId>key being incremented by both routes.