parse-community / parse-community/parse-server
Rate limit Redis keys are not scoped to the configured route
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 21.4k
- Forks
- 4.8k
- Avg merge
- 7h 45m
- Merged PRs (30d)
- 11
Description
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 keyrl:<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: 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
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the rate-limit middleware's RedisStore construction and key generator, where the issue reports that requestPath is only used for middleware selection and each store uses the default rl: prefix. Trace how rule configuration reaches Redis and add focused coverage for separate routes, windows, and multiple limits; done means independent rules no longer share keys or TTLs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, redis
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100