CVE-2026-54461: Habitica, regex injection and ReDoS in member search

CVE-2026-54461

A Habitica search field forgets to escape the input on the username: regex injection, enumeration and ReDoS.

Habitica is a gamified productivity app (open source, Node.js). The endpoint GET /api/v3/groups/:groupId/members?search=... looks up members in a group by building a MongoDB regex from the search parameter. The input is properly escaped for one field, but not for the other (website/server/controllers/api-v3/members.js):

if (req.query.search) {
  const escapedSearch = escapeRegExp(req.query.search);   // input nettoyé...
  query.$or = [
    { 'profile.name':        { $regex: new RegExp(escapedSearch, 'i') } },      // ...bien utilisé ici
    { 'auth.local.username': { $regex: new RegExp(req.query.search, 'i') } },   // mais ici : input BRUT
  ];
}

escapeRegExp (lodash) neutralizes a regex’s metacharacters. It is applied correctly on profile.name, but the line below reuses the raw req.query.search instead of escapedSearch. So on the auth.local.username field, anything you put in search is interpreted as a regex. The right variable already existed two lines above; it is simply the wrong one that got passed.

In practice, for any authenticated user who is a member of the group:

  • Username enumeration. Where a literal search returns nothing, a regex pattern surfaces members: .* returns the whole group, ^admin reveals that a username begins with admin, (?=.*secret) tests for a substring. By chaining anchored patterns you reconstruct usernames character by character.

  • ReDoS. A pattern like (a+)+$ triggers catastrophic backtracking. Since the regex is passed to MongoDB as $regex, it is the database engine that evaluates it against usernames, and the compute time grows exponentially with the length of the pattern (from a few tens of ms to several seconds). A single request is enough to spin the database CPU uselessly and freeze the response; the rate limiter (30 req/60 s) does not help, a few parallel requests are enough.