Please report security issues privately to security@uplytech.de rather than in a public issue.
| First response | within 48 hours |
| Fix or mitigation plan | within 5 working days |
| Disclosure | coordinated, after a fix is available |
Include the curve configuration, the rule involved and the sequence of calls that demonstrates the problem. Reproduction steps matter more than severity claims.
RankMode holds no credentials, opens no sockets and stores no data, so the interesting failures are of one kind: somebody being able to obtain a standing they did not earn. For the participation half that is points; for the ranked half it is a rank. Specifically:
- A way to bypass a cooldown or a period cap.
- A way to make the award computation return more than the configured maximum.
- A total that can be pushed outside the safe integer range, or made to wrap.
- A crafted
MemberStateorRankedState(from a database an attacker can influence) that makes an engine misbehave rather than raise aValidationError. - A way to gain rating or League Points from a match that did not happen, or to gain more from one than the configured formula allows.
- A rating or ladder input that makes a call raise or hang rather than return an answer. The volatility solver is the only unbounded loop in the library; it bisects, so its step count follows from the bracket width alone, and the bracket is clamped into the configured volatility bounds. A case that escapes either bound is a vulnerability, not a curiosity — see the 3.0.0 changelog for two that did before release.
- Any difference between the Python and the TypeScript edition that somebody could exploit by moving between two of an operator's communities. This includes a rating that lands one micro-unit either side of a promotion threshold in one edition and not the other.
- A denial of service from a plausible input — a curve configuration, a leaderboard size or a team-balancing group that makes a call take unreasonably long.
- Predictable awards from
SeededRandomSource/FixedRandomSource. Both classes are documented as test helpers. Using it in production is a configuration mistake, and the documentation says so in three places. - Points farmed within the configured limits. If an operator sets no cooldown and no cap, the library will do as it was told.
- Rank farmed by playing weak opponents. Both rating systems already pay almost nothing for beating somebody far below you, and that is the whole defence a rating formula offers. Detecting two accounts arranging their results is the caller's problem: RankMode is told a match happened and has no way to know whether it did.
balance_teamsrefusing more than twenty players. It is exhaustive by design; the cap is the documented boundary, not a limitation to work around.- Anything involving the caller's own database, Discord permissions or reward handling — the library has no part in those by design.
These are the two mistakes that actually cause incidents:
-
Use a cryptographic random source in production.
SystemRandomSource(Python) andCryptoRandomSource(TypeScript) are the defaults for a reason. A predictable generator lets anyone who works out the algorithm predict the next award — exactly the farming the random span was added to prevent. -
Set a cooldown and a cap. They are core functions, not optional extras. A rule with neither will be exploited; this is not a hypothetical.
Beyond that: RankMode never logs, so nothing you pass it — member ids included — appears anywhere. Everything the library learns exists only for the duration of the call.
| Version | Supported |
|---|---|
| 1.x | yes |
Security fixes ship as a patch release and are back-ported to the previous major version for six months after a new major is released.