{
  "id": 19436201,
  "title": "A search box that JOINed to your token table: ORM filter injection in KoboToolbox (GHSA-xrq7-925g-qg5m)",
  "url": "https://urgent.news/2026/11/11/a-search-box-that-joined-to-your-token-table-orm-filter-injection-in",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-11T03:19:14.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/santosh_kumarpuppala_96e/a-search-box-that-joined-to-your-token-table-orm-filter-injection-in-kobotoolbox-27g"
  },
  "original_language": "en",
  "account": "KoboToolbox, an open-source data collection platform for humanitarian action, development, environmental protection, research, and social good, discovered a vulnerability in its kpi server called ORM filter injection. This flaw, identified as GHSA-xrq7-925g-qg5m, allows authenticated users to recover parts of an owner's API token through a malicious search query. The search box in the asset table of the kpi inadvertently allowed users to construct a Django Q(**{field: value}) object, granting access to unintended fields.\n\nWhen a GET request is made to the search endpoint with a specially crafted query, the permission filter allows the user to see assets shared with them. The KpiObjectPermissionsFilter then applies the user-defined query to a permission-scoped queryset. By inserting a lookup such as owner__auth_token__key__startswith, the attacker could retrieve individual characters of the owner's API token, one at a time. Although the loop was not executed further and no token was used, the vulnerability posed a significant security risk.\n\nKoboToolbox addressed the issue in version 2.026.23a and notified self-hosted installations to update promptly. The vulnerability highlights the importance of securely implementing ORM filters in web applications, especially when sharing features are involved, to prevent unauthorized access to sensitive data.",
  "summary": "TL;DR What: The asset-search endpoint in KoboToolbox kpi built a Django Q(**{field: value}) from the field name in q= , and nothing limited which fields that name could reach. The grammar allows __ , so an authenticated user could send a relational lookup like owner__auth_token__key__startswith , which JOINs from an asset to its owner's API token. Impact: The paginated count in the response works…",
  "key_points": [
    "Authenticated users can recover parts of API tokens via malicious search queries.",
    "Search box in kpi server allows construction of Django Q({field: value}) object.",
    "KoboToolbox fixed vulnerability in version 2.026.23a, urging self-hosted installations to update."
  ],
  "editors_take": "Improperly implemented ORM filters in the KoboToolbox search functionality transform a standard data-sharing feature into a mechanism for authenticated users to systematically extract sensitive API tokens from platform owners.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}