# Directus: Authorization-dependent response served from unsegmented cache key

Directus cache key omits share/role context, so share-scoped or anonymous requests to the same URL receive another share's cached permission-filtered response.

- Payout: Research
- Severity: high
- Program: Directus
- Found by: tr4ce-ju
- Disclosed: 2026-07-20
- CVE: CVE-2026-61836
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-c6w9-5g5j-jh2p
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-c6w9-5g5j-jh2p
- Tags: area:web domain:api domain:web impact:data-leak kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:access-control vuln:cache-deception vuln:info-disclosure

**Target:** Directus REST API response cache (get-cache-key) with share tokens
**Root cause:** Cache key derivation in api/src/utils/get-cache-key.ts includes only version, path, query, accountability.user (and conditional ip), omitting share/role/roles/admin/app/policies. Share JWTs lack an id claim so accountability.user stays null, collapsing all shares and anonymous requests to user:null.
**Steps:**
1. Enable `CACHE_ENABLED=true` with at least one active `directus_shares` row.
2. Request a URL as Share A, e.g. `GET /items/articles?fields=*` with Share A's token, populating the cache under key derived from user=null.
3. Request the same URL/query with Share B's token (or anonymously, no token) within `CACHE_TTL`.
4. Observe Share A's permission-filtered payload returned without permission re-evaluation.
**How found:** Code reading of cache-key derivation: noticed authorization context beyond `user` absent from the key, then traced share JWT issuance (shares.ts:100-105) lacking an `id` claim so get-accountability-for-token.ts leaves accountability.user null, making all shares and anonymous requests collide.
**Exploitation:** Attacker holds any share token or is fully anonymous; hits the same predictable item-detail URL pattern a share request populated, receiving the cached scoped response for the CACHE_TTL window (5-30 min), surviving restarts with redis store. Read-only.
**Escalation:** Password-protected shares bypassed as a derivative symptom: once any share populates the cache, anonymous/alternate-share requests retrieve the payload without exchanging the share password. Leak scope widens when the share is backed by a role with broad field access rather than role=null.
**Insight:** When auditing cache layers, check whether the cache key includes every authorization dimension the response depends on — especially identity fields that are null for token types (share/guest JWTs) that lack an id claim, since null collapses distinct principals into one bucket.

