Skip to content

[API] CacheService.lock lacks ownership verification on release #426

@Flegma

Description

@Flegma

Summary

The CacheService.lock() implementation in api/src/cache/cache.service.ts:86-106 stores a static value 1 and does unconditional DEL in the finally block. If the lock expires mid-operation, another caller may have acquired the lock, and the first caller's finally block deletes the second caller's lock.

Findings

  • cache.service.ts:94SET lockKey 1 EX expires NX stores a fixed value, making ownership verification impossible
  • cache.service.ts:98this.forget(lockKey) does unconditional DEL, potentially releasing another caller's lock

Impact

Under high concurrency or slow callbacks, mutual exclusion guarantees are violated. This affects all code paths using cache.lock(), including server assignment and matchmaking verification.

Suggested Fix

  1. Generate a UUID per lock acquisition and store it as the lock value
  2. Use a Lua script for conditional delete: if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]) end
  3. The pattern is already demonstrated in MatchmakeService.CLAIM_LOBBY_SCRIPT

References

Found during security review of Sprint 3 audit PRs (#373, #374).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions