Description
The POST /api/architecture endpoint has no authentication. It accepts an arbitrary GitHub repository URL, embeds the server's GitHub Personal Access Token into a git clone URL, and passes it to execFile. When the clone fails (trivially triggered by providing a non-existent repo), git's stderr output includes the full URL with the embedded PAT, which is then logged verbatim via console.error.
File: app/api/architecture/route.ts
No authentication (line 260):
export async function POST(req: NextRequest) {
// No session check, no bearer token, no API key
PAT embedded in clone URL (lines 277-281):
const tokens = getGitHubTokens();
const token = tokens.length > 0 ? tokens[0] : null;
const cloneUrl = token
? `https://x-access-token:${token}@github.com/${owner}/${repo}.git`
: `https://github.com/${owner}/${repo}.git`;
Token leaked to logs on failure (line 290):
console.error('Cloning failed for repository:', repoUrl, err);
Git outputs the full clone URL (including the PAT) in its error messages:
fatal: repository 'https://x-access-token:ghp_xxxxxxxxxxxx@github.com/nonexistent/repo.git/' not found
Reproduction
curl -X POST https://<deployment>/api/architecture \
-H "Content-Type: application/json" \
-d '{"repoUrl": "https://github.com/nonexistent-owner/nonexistent-repo"}'
Impact
- Credential Compromise: The leaked PAT grants access to the application's GitHub organization repositories, including private code. Depending on token scopes, it may also grant write access, webhook management, and other organization resources.
- Zero Authentication Required: Any anonymous internet user can trigger this.
- Trivially Exploitible: A single HTTP request is sufficient.
- Persistent Exposure: Once in server logs, the PAT remains accessible to anyone with log access (team members, monitoring services, log aggregation platforms like Datadog).
Secondary Issue (Same Endpoint)
Line 596 also embeds the GEMINI_API_KEY in a URL query parameter:
const geminiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${geminiApiKey}`;
This exposes the Gemini API key to Google's server access logs, intermediary proxies, and outbound request logs.
Suggested Fix
- Add authentication to the POST handler (require a valid session or API key).
- Never embed credentials in git clone URLs. Use
GIT_ASKPASS or pass the token via environment variable so it doesn't appear in process arguments or error output.
- Sanitize error output before logging — strip
x-access-token:...@ patterns from error messages.
- Move the GEMINI_API_KEY from the URL query parameter to a request header (
x-goog-api-key).
Description
The
POST /api/architectureendpoint has no authentication. It accepts an arbitrary GitHub repository URL, embeds the server's GitHub Personal Access Token into agit cloneURL, and passes it toexecFile. When the clone fails (trivially triggered by providing a non-existent repo), git's stderr output includes the full URL with the embedded PAT, which is then logged verbatim viaconsole.error.File:
app/api/architecture/route.tsNo authentication (line 260):
PAT embedded in clone URL (lines 277-281):
Token leaked to logs on failure (line 290):
Git outputs the full clone URL (including the PAT) in its error messages:
Reproduction
Impact
Secondary Issue (Same Endpoint)
Line 596 also embeds the
GEMINI_API_KEYin a URL query parameter:This exposes the Gemini API key to Google's server access logs, intermediary proxies, and outbound request logs.
Suggested Fix
GIT_ASKPASSor pass the token via environment variable so it doesn't appear in process arguments or error output.x-access-token:...@patterns from error messages.x-goog-api-key).