Title: [Security][Medium] Unauthenticated annotation writes persist unlimited attacker-shaped files into the git-tracked .graphcoder store
Severity: Medium (CWE-400, CWE-20)
Locations: packages/server/src/routes/annotations.ts:186-207, 387-394; packages/core/src/annotations/store.ts:69-74
Summary
.graphcoder/annotations/ is git-tracked by design. POST /api/annotations writes one JSON file per call — unauthenticated, no rate limit, no quota. Only kind is length-capped (64); label/description/reasoning/members are unbounded free text. POST /api/git/pr-stack/import additionally persists commit-message-derived labels/descriptions from ANY repo the user diffs into committed files.
Evidence
routes/annotations.ts:186-207:
const annotation = createAnnotation(shape, label, members, opts)
saveAnnotation(root, annotation)
schemas (annotations.ts): label: z.string().min(1) — no max; members: z.array(z.string()).default([]) — no count cap.
Impact
An attacker page (via CORS) or a diff-view click on a malicious repo can: fill the user's disk with files; forge agent-authored review-comment content that the client renders; pre-register poisoned kind names that get committed.
Recommended fix
Add field-length/member-count caps to the schemas, rate-limit writes, and require explicit confirmation before persisting agent/imported annotations into the git-tracked store.
Title: [Security][Medium] Unauthenticated annotation writes persist unlimited attacker-shaped files into the git-tracked .graphcoder store
Severity: Medium (CWE-400, CWE-20)
Locations: packages/server/src/routes/annotations.ts:186-207, 387-394; packages/core/src/annotations/store.ts:69-74
Summary
.graphcoder/annotations/is git-tracked by design.POST /api/annotationswrites one JSON file per call — unauthenticated, no rate limit, no quota. Onlykindis length-capped (64);label/description/reasoning/membersare unbounded free text.POST /api/git/pr-stack/importadditionally persists commit-message-derived labels/descriptions from ANY repo the user diffs into committed files.Evidence
routes/annotations.ts:186-207:
schemas (annotations.ts):
label: z.string().min(1)— no max;members: z.array(z.string()).default([])— no count cap.Impact
An attacker page (via CORS) or a diff-view click on a malicious repo can: fill the user's disk with files; forge agent-authored review-comment content that the client renders; pre-register poisoned kind names that get committed.
Recommended fix
Add field-length/member-count caps to the schemas, rate-limit writes, and require explicit confirmation before persisting agent/imported annotations into the git-tracked store.