> ## Documentation Index
> Fetch the complete documentation index at: https://system.muzemus.online/llms.txt
> Use this file to discover all available pages before exploring further.

# Security boundaries

> Trust boundaries, attack surface, and security measures in MUZE

## Trust boundaries

```mermaid theme={null}
graph TB
    subgraph Untrusted["Untrusted zone"]
        Browser["User's browser"]
        Internet["Public internet"]
    end

    subgraph Firebase["Firebase Hosting (CDN)"]
        SPA["React SPA (static files only)"]
    end

    subgraph Render["Render (NestJS)"]
        API["API server"]
    end

    subgraph Neon["Neon PostgreSQL"]
        DB["Database"]
    end

    subgraph R2["Cloudflare R2"]
        Files["File storage"]
    end

    Browser -->|"HTTPS"| SPA
    SPA -->|"HTTPS + session cookie"| API
    API -->|"TLS + connection string"| DB
    API -->|"S3 API + access key"| R2
```

## Security measures

### Transport security

| Layer               | Measure                                  |
| ------------------- | ---------------------------------------- |
| Browser to Firebase | HTTPS enforced by Firebase Hosting       |
| Browser to Render   | HTTPS enforced by Render                 |
| Render to Neon      | TLS enforced by Neon (`sslmode=require`) |
| Render to R2        | HTTPS enforced by Cloudflare             |

### HTTP security headers

Helmet is applied globally:

```typescript theme={null}
helmet({
  crossOriginResourcePolicy: { policy: 'cross-origin' },
  contentSecurityPolicy: false,  // Disabled for SPA compatibility
})
```

CSP is disabled because the React SPA loads inline scripts and styles that CSP would block. This is a known trade-off tracked in [Known limitations](/engineering/known-limitations).

### Cookie security

| Attribute | Production | Development |
| --------- | ---------- | ----------- |
| HttpOnly  | `true`     | `true`      |
| Secure    | `true`     | `false`     |
| SameSite  | `None`     | `Lax`       |
| Path      | `/`        | `/`         |

`SameSite=None` is required because the frontend (Firebase) and backend (Render) sit on different origins. See [Authentication](/security/authentication).

### Input security

| Measure        | Implementation                                                           |
| -------------- | ------------------------------------------------------------------------ |
| SQL injection  | Prisma parameterized queries; no raw SQL in application code             |
| XSS            | React's JSX escaping plus Helmet headers                                 |
| CSRF           | SameSite cookies plus CORS origin restriction                            |
| Request size   | 20MB limit via `express.json`                                            |
| Unknown fields | `ValidationPipe` with `whitelist: true` and `forbidNonWhitelisted: true` |

### CORS configuration

```typescript theme={null}
app.enableCors({
  origin: allowedOrigins.length > 0 ? allowedOrigins : true,
  credentials: true,
});
```

Origins are parsed from the `FRONTEND_ORIGIN` environment variable: the Firebase Hosting URL in production, `http://localhost:5173` in development.

## Attack surface assessment

| Vector                 | Risk     | Current mitigation                                                       |
| ---------------------- | -------- | ------------------------------------------------------------------------ |
| Credential theft       | Medium   | Session cookies are HttpOnly + Secure; no JWT in localStorage            |
| Session hijacking      | Low      | Secure flag enforces HTTPS-only cookies                                  |
| SQL injection          | Very low | Prisma parameterized queries throughout                                  |
| XSS                    | Low      | React escapes JSX by default; Helmet adds headers                        |
| CSRF                   | Low      | SameSite cookies plus CORS origin check; no state-changing GET endpoints |
| Privilege escalation   | Medium   | Three-guard authorization stack plus service-layer scope checks          |
| Cross-client data leak | Medium   | Application-layer clientId filtering; no database-level RLS              |
| Denial of service      | Low      | Rate limiting at 100 req/min                                             |
| Supply chain           | Medium   | Dependencies pinned in lockfile; no automated vulnerability scanning     |

Security gaps (MFA, CSP, RLS, account lockout, and others) are tracked with priorities in [Known limitations](/engineering/known-limitations) and scheduled in [Future architecture](/engineering/future-architecture).
