Skip to content

Add a request-scoped tenant filter to the caching key namespace to prevent cross-tenant cache reads #1054

Description

@RUKAYAT-CODER

Overview

CachingService derives its counter namespace from the cache:{type}:... key convention via deriveCacheType, but nothing in the service or in CacheKeyBuilder incorporates a tenant identifier into the cache key itself. Any cached value keyed only on an entity id — a course, a search result, a dashboard aggregate — is shared across every tenant in the deployment. A tenant that requests a resource first populates the entry, and every other tenant subsequently reads it, which turns the cache into a cross-tenant disclosure channel that bypasses whatever tenant scoping the underlying query applied.

Specifications

Features:

  • Every cache key is namespaced by tenant.
  • A missing tenant context is a hard failure rather than a shared key.

Tasks:

  • Extend CacheKeyBuilder to require a tenant identifier and emit keys of the form cache:{tenant}:{type}:{id}.
  • Resolve the tenant from the request-scoped tenancy context and thread it through the caching call sites.
  • Throw rather than falling back to a global namespace when no tenant context is available in a tenant-scoped path.
  • Update deriveCacheType so counter namespacing still works with the extra segment.
  • Add an integration test that populates the cache as tenant A and asserts tenant B receives a miss.

Impacted Files:

  • src/caching/cache-key.builder.ts
  • src/caching/caching.service.ts
  • src/tenancy/

Acceptance Criteria

  • No cache key omits the tenant segment on a tenant-scoped path.
  • Tenant B never reads a value populated by tenant A.
  • Cache hit/miss counters remain correctly bucketed by type.
  • An integration test covers the cross-tenant isolation.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions