Skip to content

Unauthenticated /api/architecture endpoint leaks GitHub PAT to server logs via failed git clone #6233

@atul-upadhyay-7

Description

@atul-upadhyay-7

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

  1. Add authentication to the POST handler (require a valid session or API key).
  2. 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.
  3. Sanitize error output before logging — strip x-access-token:...@ patterns from error messages.
  4. Move the GEMINI_API_KEY from the URL query parameter to a request header (x-goog-api-key).

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions