GitHub Advisoryadvisory · npm

GHSA-c6w9-5g5j-jh2p Directus: Authorization-dependent response served from unsegmented cache key

HIGH Published 2026-07-20 Modified 2026-07-20 Official page ↗
Aliases
CVE-2026-61836
Ecosystem
npm
Packages
directus
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
Weaknesses
CWE-524, CWE-639
Reviewed
2026-07-20

Affected packages

• npm directus: < 12.0.0 → fixed in 12.0.0

Description

Summary When response caching is enabled (`CACHE_ENABLED=true`), the cache-key derivation in `api/src/utils/get-cache-key.ts` includes only `version`, `path`, `query`, and `accountability.user` (plus a conditional `ip`). Authorization context beyond `user` (`share`, `role`, `roles`, `admin`, `app`, `policies`) is not part of the key. For share tokens this is load-bearing. Directus's share-authentication flow (`api/src/services/shares.ts:100-105`) issues a JWT without an `id` claim, so `api/src/utils/get-accountability-for-token.ts` never assigns `accountability.user`, leaving it `null` (the default from `create-default-accountability.ts`). Every share token, and every anonymous request, therefore reduces to `user: null` in the cache-key input. Two different shares (or an anonymous request and a share token) requesting the same URL with the same query produce identical cache keys. The first request populates the bucket with a permission-filtered response; subsequent hits from unrelated shares or anonymous clients receive that payload without any permission re-evaluation. This is the web-cache pattern "authorization-dependent response cached under an unsegmented key" (cache key collision / missing authorization context in cache key, CWE-524 and CWE-639). Two adjacent read populations collide: • Share to share: `Share A` populates the cache, `Share B` reads `Share A`'s scoped response. • Share to anonymous (and the reverse): any unauthenticated client hitting the same URL retrieves cached share-scoped data without presenting any token. Affected • Config required: `CACHE_ENABLED=true` (any store: memory, redis, memcached) plus at least one active `directus_shares` row. This is not a default-on bug: `CACHE_ENABLED` ships as `false`. The cache is documented as a production performance setting, so operators who enable it are the ones affected. Vulnerability class • CWE-524: Use of Cache Containing Sensitive Information • CWE-639: Authorization Bypass Through User-Controlled Key (the key here is the derived cache key, not the URL) • OWASP API3:2023: Broken Object Property Level Authorization Impact • Cross-share confidentiality breach. Any share's filtered response can be served to a holder of a different share token, or to an anonymous request, that hits the same URL and query. Shares are advertised as a mechanism to distribute scoped, read-only access to specific items; this bug makes every cached share response readable by any other share-token holder who can reach the URL (the item-detail admin UI uses a predictable pattern). • Anonymous request can read share data. Anonymous requests also compute `user=null`. An anonymous client hitting `/items/articles?fields=*` after a share request has populated the cache receives the share's scoped payload with zero authentication. • Password-protected share, derivative effect. Password protection lives only at `shares.login` (JWT issuance). Once any share has populated the cache for a URL, an anonymous or alternate-share request to that URL retrieves the cached payload without exchanging the share password. This is the same cache-key collision surfacing as a password-protection bypass symptom, not a distinct mechanism. • Persistence. The leak persists for the `CACHE_TTL` window (commonly 5 to 30 minutes). `CACHE_AUTO_PURGE` clears on mutating writes to cached collections but does not purge per-user or per-share. With `CACHE_STORE=redis` (common in production) the poisoned bucket survives server restarts. • No write impact. The bypass is read-only. Scope of the leak depends on the share's permission surface. A share with no backing role (`directus_shares.role = null`, the default) collapses visibility to the primary key, so the cache leaks only PKs. A share backed by a role with broader field access (the intended production setup for distributing useful content) leaks the full content that role can see on the scoped item.

Related

Alias · CVE (1)

  • CVE-2026-61836 Directus is a real-time API and App dashboard for managing SQL database content. vulnerability

Weakness · CWE (2)

  • CWE-524 Use of Cache Containing Sensitive Information weakness
  • CWE-639 Authorization Bypass Through User-Controlled Key weakness

References