# Edge caching strategy handles personalized content

- **Pattern:** `ab-002031` (`performance-deep-dive.caching-cdn.edge-cache-personalization`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002031
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002031)

## Why it matters

CWE-525 (Information Exposure Through Browser Caching) is the formal classification, but the concrete failure is simpler: if a user-specific API response is cached at the CDN edge without `Cache-Control: private`, the next user who hits the same edge node may receive another user's private data. This is a data-exposure bug masquerading as a caching misconfiguration. ISO 25010:2011 time-behaviour flags the caching intent; the security consequence is personally identifiable or account-sensitive data served cross-user from an edge cache.

## Severity rationale

Medium because edge-caching personalized data exposes user-specific information to other users, but exploitation requires the attacker to hit the same edge node shortly after the victim — reducing but not eliminating real-world risk.

## Remediation

Every API route that returns user-specific data must set `Cache-Control: private, no-cache`. Verify this is applied at the route level, not overridden by a global CDN header rule.

```ts
// app/api/user/profile/route.ts
export async function GET(request: Request) {
  const profile = await getUserProfile(request)
  return Response.json(profile, {
    headers: { 'Cache-Control': 'private, no-cache' },
  })
}
```

## Detection

- **ID:** `edge-cache-personalization`
- **Severity:** `medium`
- **What to look for:** Count all API endpoints returning personalized/user-specific data. Enumerate their Cache-Control headers. Examine API endpoints and data-fetching patterns for personalized content (user-specific dashboards, profiles, private data). Check whether these endpoints are excluded from CDN caching via `Cache-Control: private` or other mechanisms.
- **Pass criteria:** Personalized/authenticated endpoints use `Cache-Control: private` or are not cached at all. Public content is cached at edge. Browser cache and edge cache strategies are separated. 100% of personalized endpoints must use `Cache-Control: private`.
- **Fail criteria:** Personalized endpoints are cached at edge without user differentiation, causing one user's data to be served to another. Or all endpoints use the same caching strategy regardless of personalization.
- **Skip (N/A) when:** The application has no personalized content or all content is behind authentication.

- **Cross-reference:** For stale-while-revalidate on public endpoints, see `stale-while-revalidate-apis`.
- **Detail on fail:** `"User dashboard endpoints cached with Cache-Control: public — user A's data served to user B from edge cache"` or `"All endpoints use same max-age=600 regardless of whether they are public or user-specific"`
- **Remediation:** Mark personalized content as non-cacheable at edge using `Cache-Control: private, no-cache`.

  ```ts
  // app/api/user/dashboard/route.ts — private cache
  return Response.json(userData, { headers: { 'Cache-Control': 'private, no-cache' } })
  ```

---

## External references

- cwe CWE-525
- iso-25010 time-behaviour

Taxons: access-control, performance

HTML version: https://auditbuffet.com/patterns/ab-002031
