# Feature Flags Server-Verified

- **Pattern:** `ab-002251` (`saas-authorization.access-control.feature-flags-server-verified`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002251
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002251)

## Why it matters

Hiding a UI button behind a client-side feature flag is not access control — it is presentation logic. The API endpoint behind that button remains callable by anyone who can craft a request. CWE-602 (Client-Side Enforcement of Server-Side Security) names this pattern precisely: security controls that exist only in client code are not controls at all. OWASP A01 covers the broader failure of missing server-side authorization. An attacker who skips the UI and calls the API directly will exercise the gated feature regardless of any client-side `useFeatureFlag` check.

## Severity rationale

Low severity because feature-only gating typically exposes paid features to non-paying users rather than enabling data exfiltration, but the business and billing impact is real.

## Remediation

Client-side flag checks are UX — add the same check server-side in the API route or Server Action that actually executes the gated capability. The server-side check is what counts.

```typescript
// app/api/generate/route.ts
export async function POST(req: NextRequest) {
  const session = await auth();
  if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

  // Server-side enforcement — this is the real gate
  const hasFeature = await checkFeatureFlag('ai-generation', session.user.id);
  if (!hasFeature) return NextResponse.json({ error: 'Feature not enabled' }, { status: 403 });

  // ... proceed with gated action
}
```

The client-side flag can remain for UX — it just must not be the only gate.

## Detection

- **ID:** `feature-flags-server-verified`
- **Severity:** `low`
- **What to look for:** Count all relevant instances and enumerate each. Look for feature flag usage — LaunchDarkly, PostHog feature flags, GrowthBook, or custom boolean flags in the database (`user.betaFeatures`, `org.plan`). Specifically, check whether feature-gating logic exists in API routes and Server Actions, or only in client-side components. A client-side `useFeatureFlag('ai-generation')` without a corresponding server-side check is a fail.
- **Pass criteria:** Feature-gated capabilities have their access checks in the server-side handler (API route, Server Action, or server component) before returning gated data or performing gated actions. At least 1 implementation must be verified.
- **Fail criteria:** Feature flag checks are present only in client-side components (hiding UI elements) with no corresponding API-level enforcement. The API endpoint will execute the action regardless of the flag if called directly.
- **Skip (N/A) when:** No feature flag library or feature-gating pattern detected anywhere in the codebase.
- **Detail on fail:** `"Feature flag checks found in client components but no corresponding server-side enforcement found in API routes or Server Actions for: [feature names]."` (List the affected features.)
- **Remediation:** Client-side feature flag checks are UX-only — they improve the experience but are not security controls. Always enforce the same check server-side before acting on a gated request.

  ```typescript
  // app/api/generate/route.ts
  export async function POST(req: NextRequest) {
    const session = await auth();
    if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

    // Server-side feature enforcement — this is what matters
    const hasFeature = await checkFeatureFlag('ai-generation', session.user.id);
    if (!hasFeature) return NextResponse.json({ error: 'Feature not enabled' }, { status: 403 });

    // ... proceed with action
  }
  ```

## External references

- cwe CWE-284
- cwe CWE-602
- owasp A01
- nist AC-3

Taxons: access-control

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