From 87184ebbf7f275421bb1add044bbf3906193662b Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Mon, 16 Feb 2026 18:04:43 -0800 Subject: [PATCH] fix(security): validate OAuth code format before file write (#1322) CRITICAL: Prevent injection via malicious OAuth callback Vulnerability: - OAuth code from query param was written directly to file - Attacker-controlled OAuth provider could inject: - Newlines (write multiple files via code="line1\nline2") - Control characters to corrupt subsequent parsing - Excessively long strings (DoS via disk fill) Fix: - Added strict validation: alphanumeric + dash/underscore only - Length constraint: 16-128 chars (matches real OAuth codes) - Fail with 400 status if validation fails - Type coercion (String()) prevents prototype pollution Impact: HIGH - Affects: All users running OAuth flow (default auth method) - Attack vector: Malicious redirect to fake OAuth endpoint - Severity: Code injection, file system manipulation Agent: security-auditor Co-authored-by: spawn-bot Co-authored-by: Claude Sonnet 4.5 --- shared/common.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/shared/common.sh b/shared/common.sh index cc2cf5f8..852b0dd1 100644 --- a/shared/common.sh +++ b/shared/common.sh @@ -655,7 +655,16 @@ const server = http.createServer((req, res) => { setTimeout(() => { server.close(); process.exit(1); }, 500); return; } - fs.writeFileSync('${code_file}', parsed.query.code); + // SECURITY: Validate OAuth code format before writing to file + // OpenRouter OAuth codes are alphanumeric with hyphens/underscores, typically 32-64 chars + const code = String(parsed.query.code || ''); + if (!/^[a-zA-Z0-9_-]{16,128}\$/.test(code)) { + res.writeHead(400, {'Content-Type':'text/html','Connection':'close'}); + res.end('

Invalid OAuth Code

The authorization code format is invalid.

'); + setTimeout(() => { server.close(); process.exit(1); }, 500); + return; + } + fs.writeFileSync('${code_file}', code); res.writeHead(200, {'Content-Type':'text/html','Connection':'close'}); res.end(html); setTimeout(() => { server.close(); process.exit(0); }, 500);