Title: [Security][Medium] .graphcoder/config.json AI provider config spawns arbitrary local processes; request body selects the entry
Severity: Medium (CWE-78, CWE-502)
Locations: packages/server/src/suggest/providers/index.ts:20-55; packages/server/src/suggest/providers/cli.ts:59-61; packages/server/src/routes/annotations.ts:331-363
Summary
loadProviderConfig() reads {projectRoot}/.graphcoder/config.json with no schema validation. A config entry containing a command field is instantiated as CLIProvider, which spawn()s that command with the configured args. /api/annotations/suggest and /annotations/:id/refine take a provider name from the request body with no allowlist — object indexing picks whatever key exists.
Evidence
providers/index.ts:20-23:
if ('command' in config) {
return new CLIProvider(config)
}
providers/cli.ts:59-61:
const child = spawn(this.config.command, [...this.config.args, ...extraArgs], ...)
Impact
Two scenarios:
- Drive-by chain with the project-open issue: an attacker page opens any writable path as the project (e.g. a downloaded zip staged in /tmp or the Downloads dir), then POSTs suggest with provider= → process execution from a web request.
- Malicious repo auto-weaponization: cloning a repo whose committed .graphcoder/config.json contains
{ai: {providers: {evil: {command: 'curl', args: [...]}}}} means one suggest call executes repo-controlled data as a process.
Recommended fix
Validate config.json with a zod schema; allowlist CLI commands (e.g. 'claude', 'codex'); never auto-trust .graphcoder/config.json from third-party repos without explicit user opt-in; validate the provider name against the loaded registry.
Title: [Security][Medium] .graphcoder/config.json AI provider config spawns arbitrary local processes; request body selects the entry
Severity: Medium (CWE-78, CWE-502)
Locations: packages/server/src/suggest/providers/index.ts:20-55; packages/server/src/suggest/providers/cli.ts:59-61; packages/server/src/routes/annotations.ts:331-363
Summary
loadProviderConfig()reads{projectRoot}/.graphcoder/config.jsonwith no schema validation. A config entry containing acommandfield is instantiated asCLIProvider, whichspawn()s that command with the configured args./api/annotations/suggestand/annotations/:id/refinetake aprovidername from the request body with no allowlist — object indexing picks whatever key exists.Evidence
providers/index.ts:20-23:
providers/cli.ts:59-61:
Impact
Two scenarios:
{ai: {providers: {evil: {command: 'curl', args: [...]}}}}means one suggest call executes repo-controlled data as a process.Recommended fix
Validate config.json with a zod schema; allowlist CLI commands (e.g. 'claude', 'codex'); never auto-trust .graphcoder/config.json from third-party repos without explicit user opt-in; validate the provider name against the loaded registry.