File size: 36,005 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# Threat Model β€” OmniRoute (2026-06-18)

**Status**: Authoritative. Supersedes any inline threat notes in code comments.
**Methodology**: STRIDE (Spoofing, Tampering, Repudiation, Information
Disclosure, Denial of Service, Elevation of Privilege) per endpoint.
**Scope**: v1 client API + management surface + agent dispatch + relay.
**Re-evaluation cadence**: every 90 days OR on any new public route
addition / new auth tier change.
**Owner**: security-circle lead.
**Related**: `SECURITY.md` (disclosure policy), `authz-inventory` (live
tier classification), `docs/openapi.yaml` (API surface), `docs/architecture/`
(security boundaries).

---

## 1. Trust boundaries

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Public Internet                                                    β”‚
β”‚   └── TLS termination (Caddy / cloud LB)                          β”‚
β”‚         β”‚                                                          β”‚
β”‚         β–Ό  ◀── Trust boundary 1: edge ↔ application                β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚ β”‚  Next.js App Router (3 replicas behind Caddy LB)              β”‚   β”‚
β”‚ β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚   β”‚
β”‚ β”‚    β”‚  per-route authz guards (routeGuard.ts)      β”‚           β”‚   β”‚
β”‚ β”‚    β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”‚           β”‚   β”‚
β”‚ β”‚    β”‚   β”‚ PUBLIC β”‚ β”‚CLIENT  β”‚ β”‚MANAGE  β”‚ β”‚ALWAYSβ”‚ β”‚           β”‚   β”‚
β”‚ β”‚    β”‚   β”‚ /healthβ”‚ β”‚ /v1/*  β”‚ β”‚/settn  β”‚ β”‚PROT  β”‚ β”‚           β”‚   β”‚
β”‚ β”‚    β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚           β”‚   β”‚
β”‚ β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β”‚   β”‚
β”‚ β”‚                       β–Ό         β–Ό                             β”‚   β”‚
β”‚ β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚ β”‚    β”‚  src/lib/sse/handlers   β”‚ β”‚ src/lib/localDb          β”‚   β”‚   β”‚
β”‚ β”‚    β”‚  (translator + chat)    β”‚ β”‚  (sql.js encrypted store)β”‚   β”‚   β”‚
β”‚ β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚ β”‚               β”‚                              β”‚                 β”‚   β”‚
β”‚ β”‚               β–Ό  ◀── Trust boundary 2: app ↔ upstream          β”‚   β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                 β–Ό                              β–Ό                    β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚ β”‚ Provider APIs            β”‚    β”‚ Filesystem (DB + secrets)  β”‚      β”‚
β”‚ β”‚  (OpenAI, Anthropic, …)  β”‚    β”‚  + Redis (session/quota)   β”‚      β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

**Boundary 1** (edge ↔ app): Mitigated by TLS at the edge + per-route auth gates
(`src/server/authz/routeGuard.ts` + `extractApiKey`/`isValidApiKey` in each
`route.ts`; there is no global Next.js middleware). Anything past this boundary is fully authenticated
unless explicitly in the PUBLIC tier.

**Boundary 2** (app ↔ upstream): Mitigated by per-provider key storage
in `src/lib/vault/` and the per-(token,IP) relay rate limit.

**Local-only boundary** (loopback-only routes): documented in
`src/server/authz/routeGuard.ts` as `LOCAL_ONLY_API_PREFIXES`; known
CVE class is "spawn capable route exposed to non-local traffic"
(GHSA-fhh6-4qxv-rpqj).

---

## 2. STRIDE legend

| Letter | Threat                 | Question it answers                                   |
| ------ | ---------------------- | ----------------------------------------------------- |
| **S**  | Spoofing               | Can an attacker pretend to be a legitimate principal? |
| **T**  | Tampering              | Can an attacker modify data in transit or at rest?    |
| **R**  | Repudiation            | Can a principal deny an action they took?             |
| **I**  | Information disclosure | Can an attacker read data they shouldn't?             |
| **D**  | Denial of service      | Can an attacker degrade or block service?             |
| **E**  | Elevation of privilege | Can an attacker gain more access than intended?       |

Severity scale: **L**ow (paper), **M**edium (real exploit possible), **H**igh
(active exploitation likely or already seen in the wild).

---

## 3. Per-endpoint STRIDE analysis (top-20 highest-risk routes)

The 50 v1 route handlers are scored below. Top-20 highest-risk routes
get a full STRIDE row; the remaining 30 are covered by a tier-level
summary in Β§ 4.

### 3.1 `/api/v1/responses` β€” POST (primary inference)

| STRIDE | Risk                                            | Mitigation                                                                                                                                                           |
| ------ | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **S**  | M β€” Bearer key stolen β†’ caller identity spoofed | Keys hashed (SHA-256) at rest in `src/lib/db/apiKeys.ts`; revocation list in `src/lib/db/apiKeys.ts#revokeKey`                                                       |
| **T**  | M β€” Request body modified in transit            | TLS at edge; body re-validated against `ResponsesRequest` schema in `open-sse/handlers/responseSanitizer.ts`                                                         |
| **R**  | L β€” Caller denies a request                     | `src/lib/audit/` writes append-only row with `key_id`, `request_hash`, `model`, `tokens`; hash-chain integrity (DEBT-051 follow-up)                                  |
| **I**  | M β€” Provider API key leaked via response        | `open-sse/handlers/responseTranslator.ts` strips `x-api-key` headers before proxying; response redaction middleware                                                  |
| **D**  | H β€” High-cost model invocation = $$ DoS         | Per-key rate limit (`open-sse/services/rateLimitManager.ts`); per-tenant quota pool (`src/lib/db/quotaPools.ts`); DEBT-001 TPM/TPD reservoir is **not** yet enforced |
| **E**  | L β€” Bearer scope escalation                     | API keys carry explicit `scopes` array; routes require specific scopes; `requireManagementAuth` enforces management tier                                             |

### 3.2 `/api/v1/relay/chat/completions` β€” POST (serverless relay)

| STRIDE | Risk                           | Mitigation                                                                                                                            |
| ------ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| **S**  | M β€” Relay token theft          | Tokens hashed with SHA-256 + per-token ID column; per-(token,IP) rate limit in `src/app/api/v1/relay/chat/completions/route.ts:38-58` |
| **T**  | M β€” Token rotation bypass      | Token records have `revoked_at`; check happens before each request                                                                    |
| **R**  | L β€” Forensic headers sanitized | `sanitizeForensicHeader` strips CR/LF; length cap 256; IP/UA never echoed back to client                                              |
| **I**  | H β€” IP-bucket map leaks        | In-memory only, per-instance, capped at 10,000 entries; not persisted; see DEBT-038 (in-memory state loss on restart)                 |
| **D**  | M β€” Per-(token,IP) abuse       | `RELAY_IP_PER_MINUTE=30` default; attacker rotates IPs to spread, hits per-token wall                                                 |
| **E**  | M β€” Token scope creep          | Tokens carry `allowedModels[]`; reject on model-not-in-list                                                                           |

### 3.3 `/api/v1/embeddings` β€” POST

| STRIDE | Risk                                                  | Mitigation                                                                      |
| ------ | ----------------------------------------------------- | ------------------------------------------------------------------------------- |
| **S**  | L β€” Same as 3.1                                       | Same auth + key model                                                           |
| **T**  | L β€” Inputs are vectors; tampered embedding not useful | Re-encode on receive; reject dimension mismatch                                 |
| **R**  | L                                                     | `src/lib/audit/` row written                                                    |
| **I**  | M β€” Embedding vectors can leak training data          | Reject requests with PII patterns (regex) before forwarding; DEBT-052 follow-up |
| **D**  | L β€” Embeddings cheaper than chat                      | Quota pool cap                                                                  |
| **E**  | L                                                     | Bearer scope                                                                    |

### 3.4 `/api/v1/rerank` β€” POST

| STRIDE | Risk                               | Mitigation                                                         |
| ------ | ---------------------------------- | ------------------------------------------------------------------ |
| **S**  | L                                  | Same auth                                                          |
| **T**  | L                                  |                                                                    |
| **R**  | L                                  |                                                                    |
| **I**  | M β€” Documents contain user content | Per-tenant key isolation; audit log captures doc hash, not content |
| **D**  | L                                  |                                                                    |
| **E**  | L                                  |                                                                    |

### 3.5 `/api/v1/moderations` β€” POST

| STRIDE | Risk                                             | Mitigation                                                           |
| ------ | ------------------------------------------------ | -------------------------------------------------------------------- |
| **S**  | L                                                |                                                                      |
| **T**  | L                                                |                                                                      |
| **R**  | L                                                |                                                                      |
| **I**  | H β€” Moderation inputs are sensitive user content | Encrypted in transit (TLS); not logged; flag results cached with TTL |
| **D**  | L                                                |                                                                      |
| **E**  | L                                                |                                                                      |

### 3.6 `/api/v1/audio/speech` β€” POST (TTS)

| STRIDE | Risk                                | Mitigation                                 |
| ------ | ----------------------------------- | ------------------------------------------ |
| **S**  | L                                   |                                            |
| **T**  | L                                   |                                            |
| **R**  | L                                   |                                            |
| **I**  | L β€” Audio is synthesised from input | Same as 3.1                                |
| **D**  | M β€” Long TTS = bandwidth burn       | `input` cap 4096 chars; per-key rate limit |
| **E**  | L                                   |                                            |

### 3.7 `/api/v1/audio/transcriptions` β€” POST (STT, multipart)

| STRIDE | Risk                                        | Mitigation                                                                                                                                                |
| ------ | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **S**  | L                                           |                                                                                                                                                           |
| **T**  | M β€” Multipart body tampered                 | `multipart-parser` validates Content-Length + boundary; size cap 25 MB                                                                                    |
| **R**  | L                                           |                                                                                                                                                           |
| **I**  | H β€” Audio contains user PII / secrets       | TTL cache; never written to disk by default; redaction of credit-card-like sequences in `open-sse/executors/chatgpt-web.ts` (per-file TODO, see DEBT-019) |
| **D**  | M β€” Large audio = bandwidth + provider cost | 25 MB cap; rate limit                                                                                                                                     |
| **E**  | L                                           |                                                                                                                                                           |

### 3.8 `/api/v1/images/generations` β€” POST

| STRIDE | Risk                                 | Mitigation                                                                                                                                |
| ------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **S**  | L                                    |                                                                                                                                           |
| **T**  | L                                    |                                                                                                                                           |
| **R**  | L                                    |                                                                                                                                           |
| **I**  | L β€” Generated images are public URLs | URLs are signed with TTL; provider-controlled CDN                                                                                         |
| **D**  | M β€” Image gen is $expensive          | Per-key USD spend limits enforced in the request pipeline (`src/lib/db/tokenLimits.ts`, surfaced via `src/app/api/usage/budget/route.ts`) |
| **E**  | L                                    |                                                                                                                                           |

### 3.9 `/api/v1/videos/generations` β€” POST (async)

| STRIDE | Risk                                          | Mitigation                                                                                    |
| ------ | --------------------------------------------- | --------------------------------------------------------------------------------------------- |
| **S**  | L                                             |                                                                                               |
| **T**  | L                                             |                                                                                               |
| **R**  | M β€” Long-running async job, hard to attribute | Job records include `key_id`, `request_id`, `created_at`; result includes signed URL with TTL |
| **I**  | M β€” Generated video may contain PII           | Same as 3.8                                                                                   |
| **D**  | M β€” Video gen is very $expensive              | Cost-budget middleware; max 10-second durations                                               |
| **E**  | L                                             |                                                                                               |

### 3.10 `/api/v1/files` β€” POST (multipart upload)

| STRIDE | Risk                                      | Mitigation                                                                                       |
| ------ | ----------------------------------------- | ------------------------------------------------------------------------------------------------ |
| **S**  | M β€” Uploaded file attributed to wrong key | `key_id` captured at upload; immutable record                                                    |
| **T**  | H β€” Malicious file (zip bomb, polyglot)   | Size cap 25 MB; MIME sniff + magic-byte check; AV scan is **not** performed (DEBT-053 follow-up) |
| **R**  | L                                         |                                                                                                  |
| **I**  | H β€” Files contain user PII                | Encrypted at rest in `src/lib/vault/`; per-tenant access control                                 |
| **D**  | M β€” Large uploads                         | Size cap + rate limit                                                                            |
| **E**  | L                                         |                                                                                                  |

### 3.11 `/api/v1/files/{id}/content` β€” GET

| STRIDE | Risk                                      | Mitigation                                                                 |
| ------ | ----------------------------------------- | -------------------------------------------------------------------------- |
| **S**  | H β€” IDOR (file belonging to other tenant) | Per-tenant scope check; `requireTenantScope` middleware (added in v3.8.25) |
| **T**  | L                                         |                                                                            |
| **R**  | L                                         |                                                                            |
| **I**  | H β€” Tenant isolation breach = data leak   | Per-tenant prefix in file storage; cross-tenant read attempt logged + 403  |
| **D**  | L                                         |                                                                            |
| **E**  | L                                         |                                                                            |

### 3.12 `/api/v1/batches` β€” POST (create batch)

| STRIDE | Risk                                       | Mitigation                                               |
| ------ | ------------------------------------------ | -------------------------------------------------------- |
| **S**  | L                                          |                                                          |
| **T**  | M β€” Batch input file modified after upload | Content hash stored at upload; mismatch on read = reject |
| **R**  | L                                          |                                                          |
| **I**  | M β€” Input file contains PII                | Same as 3.10                                             |
| **D**  | M β€” Large batch                            | 50k row cap per batch                                    |
| **E**  | L                                          |                                                          |

### 3.13 `/api/v1/batches/delete-completed` β€” POST

| STRIDE | Risk                                          | Mitigation                                                                                |
| ------ | --------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **S**  | L                                             |                                                                                           |
| **T**  | H β€” Mass delete                               | Requires manage-scope auth; `requireManagementAuth` enforced; audit log captures `key_id` |
| **R**  | L                                             |                                                                                           |
| **I**  | M β€” Output files may leak                     | Soft-delete with 7-day retention before GC                                                |
| **D**  | L                                             |                                                                                           |
| **E**  | M β€” A misconfigured client could trigger this | Auth gate prevents; no anonymous access                                                   |

### 3.14 `/api/v1/agents/tasks` β€” POST (cloud-agent dispatch)

| STRIDE | Risk                                     | Mitigation                                                                                                                |
| ------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **S**  | L                                        |                                                                                                                           |
| **T**  | H β€” Prompt injection in task `prompt`    | `withInjectionGuard` middleware (per `src/app/api/v1/responses/route.ts:6`); pattern blocklist + sandboxed tool execution |
| **R**  | M β€” Long-running agent task, attribution | Task ID + `key_id` + `created_at` recorded; agent result signed by provider                                               |
| **I**  | H β€” Agent reads user repo / credentials  | Provider-scoped credentials; least-privilege OAuth; agent result sandboxed before return                                  |
| **D**  | M β€” Long-running agent = $$ burn         | 10-minute default timeout; configurable `timeoutSeconds`                                                                  |
| **E**  | M β€” Agent tool calls could exceed scope  | Tool allowlist per provider; rejection in `open-sse/executors/`                                                           |

### 3.15 `/api/v1/agents/credentials` β€” GET (list stored creds)

| STRIDE | Risk                                                     | Mitigation                                                                                     |
| ------ | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| **S**  | L                                                        |                                                                                                |
| **T**  | L                                                        |                                                                                                |
| **R**  | L                                                        |                                                                                                |
| **I**  | H β€” Leaked credential metadata enables targeted phishing | Returns only `provider`, `hasValue`, `updatedAt` (NEVER the value); requires manage-scope auth |
| **D**  | L                                                        |                                                                                                |
| **E**  | L                                                        |                                                                                                |

### 3.16 `/api/v1/me/status` β€” GET (caller introspection)

| STRIDE | Risk                                                 | Mitigation                                     |
| ------ | ---------------------------------------------------- | ---------------------------------------------- |
| **S**  | L                                                    |                                                |
| **T**  | L                                                    |                                                |
| **R**  | L                                                    |                                                |
| **I**  | M β€” Reveals quota usage; could enable timing attacks | Rate-limited; per-key only; no cross-key reads |
| **D**  | L                                                    |                                                |
| **E**  | L                                                    |                                                |

### 3.17 `/api/v1/providers/{provider}/models` β€” GET

| STRIDE | Risk                           | Mitigation                            |
| ------ | ------------------------------ | ------------------------------------- |
| **S**  | L                              |                                       |
| **T**  | L                              |                                       |
| **R**  | L                              |                                       |
| **I**  | M β€” Reveals provider allowlist | Required for client UX; per-key scope |
| **D**  | L                              |                                       |
| **E**  | L                              |                                       |

### 3.18 `/api/v1/web/fetch` β€” POST (server-side fetch)

| STRIDE | Risk                                                          | Mitigation                                                                                                    |
| ------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **S**  | L                                                             |                                                                                                               |
| **T**  | L                                                             |                                                                                                               |
| **R**  | L                                                             |                                                                                                               |
| **I**  | H β€” Fetched content could be exfiltrated via prompt injection | Content goes through `withInjectionGuard`; explicit extract modes; URL allowlist (default-deny, see DEBT-054) |
| **D**  | M β€” Recursive fetch = bandwidth burn                          | Max redirects 3; max 5 MB response; timeout 10s                                                               |
| **E**  | L                                                             |                                                                                                               |

### 3.19 `/api/v1/vscode/{token}/v1/chat/completions` β€” POST (VSCode shim)

| STRIDE | Risk                                              | Mitigation                                                                                |
| ------ | ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **S**  | M β€” VSCode token theft = long-lived impersonation | Tokens are 256-bit, single-purpose, scoped to VSCode-CLI; revokable from `/api/keys/{id}` |
| **T**  | L                                                 |                                                                                           |
| **R**  | L                                                 |                                                                                           |
| **I**  | M β€” Token in URL = logged in access logs          | Token treated as secret; logs hash + last-4 only                                          |
| **D**  | M β€” Per-token rate limit (lower than API key)     | `VSCODECLI_RATE_LIMIT=10` req/min default                                                 |
| **E**  | L                                                 |                                                                                           |

### 3.20 `/api/v1/ws` β€” WebSocket

| STRIDE | Risk                                            | Mitigation                                                                                    |
| ------ | ----------------------------------------------- | --------------------------------------------------------------------------------------------- |
| **S**  | M β€” WS upgrade lacks standard Bearer header     | Subprotocol-based auth: `Sec-WebSocket-Protocol: bearer, <token>`; per-connection scope check |
| **T**  | M β€” WS message frames tampered                  | TLS-only (`wss://`); reject `ws://` in prod                                                   |
| **R**  | L                                               | Connection ID + auth principal recorded at handshake                                          |
| **I**  | H β€” Long-lived connection = larger blast radius | 1-hour max connection; heartbeat every 30s; auto-disconnect on auth revoke                    |
| **D**  | H β€” Many WS = connection table exhaustion       | Per-IP WS cap 5; per-key cap 20; rate limit per message                                       |
| **E**  | L                                               |                                                                                               |

---

## 4. Tier-level summary (remaining 30 routes)

Routes in the same tier inherit the same baseline mitigations. Per-route
deltas are documented in `docs/openapi.yaml` (request schema constraints).

| Tier                                                                                                                                | Count | Baseline mitigations                                       | Residual risks                       |
| ----------------------------------------------------------------------------------------------------------------------------------- | ----- | ---------------------------------------------------------- | ------------------------------------ |
| PUBLIC (`/api/health`, `/api/monitoring/health`, `/_next/*`)                                                                        | 3     | No auth; rate limit; static response                       | DoS via flooding (mitigated at LB)   |
| CLIENT_API inference (`/v1/audio`, `/v1/moderations`, `/v1/rerank`, `/v1/search`, `/v1/embeddings`, `/v1/responses`, `/v1/relay/*`) | 8     | Bearer auth + per-key rate limit + audit log + cost budget | TPM/TPD fairness (DEBT-001)          |
| CLIENT_API files (`/v1/files`, `/v1/files/{id}`, `/v1/batches/*`)                                                                   | 5     | Bearer auth + per-tenant prefix + AV scan absent           | DEBT-053 (AV)                        |
| CLIENT_API combos/me/providers                                                                                                      | 3     | Bearer auth + cached                                       | None material                        |
| CLIENT_API vscode shim                                                                                                              | 13    | Token-scoped + per-token rate limit                        | Token in URL log noise               |
| MANAGEMENT (`/api/settings/*`, `/api/keys/*`, `/api/quota/*`, `/api/usage/*`)                                                       | ~60   | Manage-scope + dashboard session + 2FA suggested           | See SECURITY.md for P0 items         |
| ALWAYS_PROTECTED (shutdown, DB settings)                                                                                            | ~5    | Auth + re-auth for security-impacting changes              | None material                        |
| LOCAL_ONLY (loopback spawn routes)                                                                                                  | ~8    | Loopback-only + bypass-constant gated by manage-scope      | GHSA-fhh6-4qxv-rpqj class if exposed |

---

## 5. Mitigations to add (next quarter)

| ID    | Mitigation                                                       | Pillar target | Effort |
| ----- | ---------------------------------------------------------------- | ------------- | ------ |
| TM-01 | DEBT-001: TPM/TPD token-bucket fairness for relay + inference    | D, E (cost)   | M      |
| TM-02 | DEBT-051: Hash-chain integrity for `src/lib/audit/` rows         | R             | M      |
| TM-03 | DEBT-053: AV scan on `/v1/files` upload (ClamAV or external API) | T, I          | L      |
| TM-04 | DEBT-054: URL allowlist for `/v1/web/fetch`                      | I, D          | M      |
| TM-05 | OIDC/SAML SSO for management tier (audit L46)                    | S             | L      |
| TM-06 | TOTP MFA for manage-scope users (audit L49)                      | S, E          | M      |
| TM-07 | Field-level encryption for PII columns (audit L47)               | I             | L      |

---

## 6. Review log

| Date                 | Reviewer                  | Change                                                                 |
| -------------------- | ------------------------- | ---------------------------------------------------------------------- |
| 2026-06-18           | @KooshaPari/core (L5-118) | Initial STRIDE per endpoint, top-20 highest-risk routes + tier summary |
| 2026-06-25 (planned) | security-circle           | Re-score after DEBT-001, DEBT-051 close-outs                           |
| 2026-09-18 (planned) | security-circle           | Quarterly full re-review; refresh mitigations list                     |