# Shared Resources Have Access Controls

- **Pattern:** `ab-002235` (`saas-authorization.resource-auth.shared-resources-access-controls`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002235
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002235)

## Why it matters

Shared and team resources introduce a second authorization dimension: not just "is the user authenticated?" but "is the user a member of the group that owns this resource?" Skipping the membership check (CWE-639, CWE-284) means any authenticated user who knows a team project ID can read or modify it. OWASP A01 (Broken Access Control) explicitly covers this: authorization must verify the relationship between the principal and the resource, not just that a session exists. NIST 800-53 AC-3 requires access enforcement to reflect actual entitlements — membership in the owning group is the entitlement for shared resources.

## Severity rationale

High because the attack surface is every authenticated user in the system, not just attackers who have compromised specific accounts.

## Remediation

Before serving any shared resource, verify the requesting user is a member of the group that owns it. Do this as a database query, not as a client-supplied parameter.

```typescript
// app/api/teams/[teamId]/projects/route.ts
const membership = await db.teamMember.findFirst({
  where: { teamId: params.teamId, userId: session.user.id },
});
if (!membership) return NextResponse.json({ error: 'Not found' }, { status: 404 });

// Membership confirmed — safe to return team data
const projects = await db.project.findMany({ where: { teamId: params.teamId } });
```

Separating the membership check from the data query (rather than using a join) makes the authorization step explicit and resistant to accidental removal in future refactors.

## Detection

- **ID:** `shared-resources-access-controls`
- **Severity:** `high`
- **What to look for:** Count all relevant instances and enumerate each. Look for "shared" or "team" concepts in the data model — shared documents, team projects, workspace resources, or any resource accessible by multiple users. When a route serves a shared resource, does it verify that the requesting user is a member of the group that owns the resource? Check for membership table queries (e.g., `teamMembers`, `projectAccess`, `workspaceMembers`) before returning shared data.
- **Pass criteria:** Routes that serve shared resources explicitly verify the requesting user's membership in the owning group before returning data, either through a membership table query or through a relationship verified in the database query itself. At least 1 implementation must be verified.
- **Fail criteria:** Shared resources are accessible to any authenticated user who knows (or can guess) the resource ID, with no check that the user is a member of the group that owns the resource.
- **Skip (N/A) when:** The application is single-user only and has no shared or collaborative resource concept.
- **Detail on fail:** `"Shared resource endpoint does not verify group membership before returning data. Any authenticated user can access shared resources by ID."` (Note the specific routes.)
- **Remediation:** Verify membership in the group that owns the resource before granting access.

  ```typescript
  // app/api/teams/[teamId]/projects/route.ts
  const membership = await db.teamMember.findFirst({
    where: { teamId: params.teamId, userId: session.user.id },
  });
  if (!membership) return NextResponse.json({ error: 'Not found' }, { status: 404 });

  // Now safe to return team projects
  const projects = await db.project.findMany({ where: { teamId: params.teamId } });
  ```

  Using `findFirst` for the membership check followed by an early return is the correct pattern — it avoids a join that could be accidentally omitted in future refactors.

## External references

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

Taxons: access-control

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