AntFleet

Disagreement · 6017bf3f-anthropic-0

Missing authentication/authorization on secret-management endpoints

mismatch
repo 6f7fc663·PR #25·reviewed 1 week ago

Primary finding

Missing authentication/authorization on secret-management endpoints

criticalsecurityhigh
  • dashboard/app/api/secrets/route.ts:95-145
  • dashboard/app/api/auth/route.ts:50-110
Both route handlers expose the ability to read which secrets are set, create/overwrite arbitrary GitHub Actions secrets (including ANTHROPIC_API_KEY / CLAUDE_CODE_OAUTH_TOKEN), and delete them. There is no authentication, no session check, no CSRF token, and no origin/host verification. If the Next.js dashboard is ever exposed beyond localhost (or reachable from a browser visiting a malicious page that POSTs JSON with a simple Content-Type to bypass CORS preflight is harder, but a curl/proxy or LAN attacker still trivially exploits it), an attacker can overwrite repo-level secrets with attacker-controlled values, exfiltrate via subsequent workflow runs, or wipe production credentials. Even on localhost, any other process on the machine can hit the endpoint. There is also no rate limiting.

Recommendation

Require authentication for all mutating routes (and arguably GET, which leaks which secrets exist). At minimum, bind the dev server to 127.0.0.1, verify a same-origin/Host header, require a CSRF token, and gate behind a session cookie or local-only token. Also reject requests if NODE_ENV === 'production' unless an explicit admin gate is satisfied.

Counterpart finding

Secrets endpoint passes secret value via command-line args (-b), exposing secrets to other processes

highsecurityhigh
  • dashboard/app/api/secrets/route.ts:112-116
  • dashboard/app/api/auth/route.ts:63-66
In POST /api/secrets, the secret value is supplied using '-b', which puts the secret on the process command line (argv). On many systems, process arguments are visible to other users and may be logged, leaking the secret. The auth route correctly uses stdin to provide the secret, avoiding this leak.

Recommendation

Provide the secret via stdin instead of '-b'. For example: execFileSync('gh', ['secret','set', name, ...ghArgsRepo()], { input: value, stdio: ['pipe','pipe','pipe'] }). Also ensure no logging of the value.

Why this didn't post

This finding didn't meet AntFleet's unanimous agreement threshold. Both frontier models review every PR independently; only findings they both flag with the same severity and category are posted to the PR. This one fell through.

read the methodology →