messages[].content and pageContext in assistant-procedure-support.ts have no .max(). An authenticated user can submit 50 MB per message × 200 messages ⇒ 10 GB of text → AI-cost DoS, memory blow-up during JSON parse & prompt assembly.
Evidence
packages/api/src/router/assistant-procedure-support.ts:47-54 — content: z.string() (no max)
packages/api/src/router/assistant-procedure-support.ts:54 — pageContext: z.string().optional() (no max)
packages/api/src/router/project-cover.ts:67-69 — DALL-E/Gemini prompt user-input concatenated directly, no injection-guard
Impact
Any authenticated user can: (a) burn thousands of dollars in AI-provider costs in minutes, (b) OOM the API process via JSON parsing, (c) inject directives into DALL-E/Gemini via project-cover prompt (no checkPromptInjection there).
Proposed Fix
content: z.string().max(10_000), pageContext: z.string().max(2_000). Compute aggregate message budget (e.g., 50 KB) and reject when exceeded. Apply checkPromptInjection() to project-cover.prompt.
Acceptance Criteria
All assistant input fields have explicit .max()
Unit test: 10 MB message rejected with 400
project-cover prompt path runs through checkPromptInjection()
## Problem
`messages[].content` and `pageContext` in assistant-procedure-support.ts have no `.max()`. An authenticated user can submit 50 MB per message × 200 messages ⇒ 10 GB of text → AI-cost DoS, memory blow-up during JSON parse & prompt assembly.
## Evidence
- `packages/api/src/router/assistant-procedure-support.ts:47-54 — content: z.string() (no max)`
- `packages/api/src/router/assistant-procedure-support.ts:54 — pageContext: z.string().optional() (no max)`
- `packages/api/src/router/project-cover.ts:67-69 — DALL-E/Gemini prompt user-input concatenated directly, no injection-guard`
## Impact
Any authenticated user can: (a) burn thousands of dollars in AI-provider costs in minutes, (b) OOM the API process via JSON parsing, (c) inject directives into DALL-E/Gemini via project-cover prompt (no `checkPromptInjection` there).
## Proposed Fix
`content: z.string().max(10_000)`, `pageContext: z.string().max(2_000)`. Compute aggregate message budget (e.g., 50 KB) and reject when exceeded. Apply `checkPromptInjection()` to `project-cover.prompt`.
## Acceptance Criteria
- [ ] All assistant input fields have explicit `.max()`
- [ ] Unit test: 10 MB message rejected with 400
- [ ] project-cover prompt path runs through checkPromptInjection()
---
Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (B-2, B-15)
Resolved. packages/api/src/router/assistant-procedure-support.ts:49-77 now enforces:
content: z.string().max(10_000) per message
pageContext: z.string().max(2_000)
conversationId: z.string().max(120)
Aggregate cap via superRefine: 200 KB across all messages + pageContext
.min(1).max(200) messages array
packages/api/src/router/project-cover.ts:37-56 now runs checkPromptInjection(input.prompt) on the user's additional-direction field and rejects with BAD_REQUEST on a hit.
Tests: packages/api/src/__tests__/assistant-input-bounds.test.ts covers all four limits with both accept + reject cases.
All acceptance criteria met — closing.
Resolved. `packages/api/src/router/assistant-procedure-support.ts:49-77` now enforces:
- `content: z.string().max(10_000)` per message
- `pageContext: z.string().max(2_000)`
- `conversationId: z.string().max(120)`
- Aggregate cap via `superRefine`: 200 KB across all messages + pageContext
- `.min(1).max(200)` messages array
`packages/api/src/router/project-cover.ts:37-56` now runs `checkPromptInjection(input.prompt)` on the user's additional-direction field and rejects with BAD_REQUEST on a hit.
Tests: `packages/api/src/__tests__/assistant-input-bounds.test.ts` covers all four limits with both accept + reject cases.
All acceptance criteria met — closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
messages[].contentandpageContextin assistant-procedure-support.ts have no.max(). An authenticated user can submit 50 MB per message × 200 messages ⇒ 10 GB of text → AI-cost DoS, memory blow-up during JSON parse & prompt assembly.Evidence
packages/api/src/router/assistant-procedure-support.ts:47-54 — content: z.string() (no max)packages/api/src/router/assistant-procedure-support.ts:54 — pageContext: z.string().optional() (no max)packages/api/src/router/project-cover.ts:67-69 — DALL-E/Gemini prompt user-input concatenated directly, no injection-guardImpact
Any authenticated user can: (a) burn thousands of dollars in AI-provider costs in minutes, (b) OOM the API process via JSON parsing, (c) inject directives into DALL-E/Gemini via project-cover prompt (no
checkPromptInjectionthere).Proposed Fix
content: z.string().max(10_000),pageContext: z.string().max(2_000). Compute aggregate message budget (e.g., 50 KB) and reject when exceeded. ApplycheckPromptInjection()toproject-cover.prompt.Acceptance Criteria
.max()Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (B-2, B-15)
Resolved.
packages/api/src/router/assistant-procedure-support.ts:49-77now enforces:content: z.string().max(10_000)per messagepageContext: z.string().max(2_000)conversationId: z.string().max(120)superRefine: 200 KB across all messages + pageContext.min(1).max(200)messages arraypackages/api/src/router/project-cover.ts:37-56now runscheckPromptInjection(input.prompt)on the user's additional-direction field and rejects with BAD_REQUEST on a hit.Tests:
packages/api/src/__tests__/assistant-input-bounds.test.tscovers all four limits with both accept + reject cases.All acceptance criteria met — closing.