CVE-2026-61836High· 8.6▾ TwilightDirectus: Authorization-dependent response served from unsegmented cache key
▾ Twilight zone — High severity, or a signal on a lesser flaw
impact 47.3 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Jul 20.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.3%
0.3% → 0.5%
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 A populates the cache, Share B reads Share A's scoped response.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.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.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.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.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.
directus < 12.0.0Upgrade to a patched release:
directus 12.0.0Connected by shared product, vendor, weakness, or advisory.
CVE-2026-61835High· 7.7Directus: SSRF Protection Bypass via 0.0.0.0 in File Import
CVE-2024-39896High· 7.5Directus Allows Single Sign-On User Enumeration
CVE-2021-46416High· 8.1Insecure direct object reference in SUNNY TRIPOWER 5.0 Firmware version 3.10.16.R leads to unauthorized user groups accessing due to insecure cookie handling.
CVE-2026-49858Medium· 5.9API Platform Core vulnerable to cross-user attribute leak in JSON:API and HAL item normalizers due to missing isCacheKeySafe gate
CVE-2025-14459High· 8.5A flaw was found in KubeVirt Containerized Data Importer (CDI)
CVE-2026-20897Critical· 9.1Gitea does not properly validate repository ownership when deleting Git LFS locks