Skip to content

[security]: Badge API endpoints /api/badge/streak and /api/badge/commits accept any arbitrary GitHub username with no input validation — username injection can trigger unbounded GitHub API calls and SSRF-adjacent abuse #2925

Closed

Description

@divyanshim27

Problem Statement

BADGE_API.md documents two public, unauthenticated badge endpoints:
GET /api/badge/streak?user=

GET /api/badge/commits?user=

The documentation explicitly states:

"Public Access: No authentication required"
"No Auth Required: Uses publicly available GitHub data"

However, the user query parameter is passed directly into GitHub API
search queries with no validation, sanitization, or allowlisting
against DevTrack's own user database.

Exact Vulnerabilities

1. Unbounded GitHub API consumption:

# Attacker loops through usernames, consuming the platform's API quota
for i in {1..1000}; do
  curl "https://devtrack-delta.vercel.app/api/badge/streak?user=user$i"
done
# Each request: 1 GitHub API call (unauthenticated: 60/hour limit hit fast)
# Result: All legitimate users' dashboards break with 403 rate-limit errors

2. Username injection into GitHub search query:

The badge endpoint constructs GitHub API search queries like:
GET https://api.github.com/search/commits?q=author:&...
If user is not validated as a valid GitHub username pattern
([a-zA-Z0-9-]+, max 39 chars), specially crafted values can
manipulate the search query:
?user=octocat+OR+author:admin # query injection

?user=<script>alert(1)</script> # XSS in SVG output if not escaped

3. BADGE_API.md documents inconsistency — rate limiting described twice with different values:

  • Body: "The DevTrack badge API itself has no rate limits"
  • Footer section: "Badge requests are restricted to 100 per minute per IP"

These contradict each other. The implementation of one or both is unclear.

Proposed Solution

Add input validation at the top of both badge route handlers:

// app/api/badge/streak/route.ts
const GITHUB_USERNAME_REGEX = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$/;

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const user = searchParams.get('user');

  if (!user || !GITHUB_USERNAME_REGEX.test(user)) {
    return new Response(generateErrorBadge('invalid user'), {
      status: 400,
      headers: { 'Content-Type': 'image/svg+xml;charset=utf-8' },
    });
  }

  // Also verify user exists in DevTrack's Supabase users table
  const { data } = await supabase
    .from('users')
    .select('github_login')
    .eq('github_login', user)
    .single();

  if (!data) {
    return new Response(generateErrorBadge('user not found'), {
      status: 404,
      headers: { 'Content-Type': 'image/svg+xml;charset=utf-8' },
    });
  }
  // ... proceed
}

Also resolve the BADGE_API.md contradiction — document one consistent
rate limit value and confirm it is actually implemented.

Feature Area

API / Backend

Alternatives Considered

No response

Acceptance Criteria

  • ...
  • ...

Additional Context

Acceptance Criteria

  • user parameter validated against GitHub username regex before
    any API call
  • Only DevTrack-registered users can generate badges (Supabase lookup)
  • SVG output HTML-encodes all user-supplied values to prevent XSS
  • BADGE_API.md contradiction between rate limit statements resolved
  • Unit test: invalid username → 400 SVG error badge; valid → 200 SVG

Labels: security, bug, backend, level: intermediate

Activity

  1. github-actions commented on Jun 29, 2026

    @github-actions

    Thanks for opening your first issue on DevTrack! 🎉

    A maintainer will take a look shortly. In the meantime:

    If you find DevTrack useful, a ⭐ star on the repo is always appreciated — it helps the project reach more developers!

  2. divyanshim27 commented on Jun 29, 2026

    @divyanshim27
    Author

    Hey @Priyanshu-byte-coder ,
    I have deeply gone through the project repo and understood and analysed the project through local running & testing , based on which I found this as major lagging/point of enhancement .
    Based on my skill-set and problem understanding , I would want to work on the issue and contribute to the repo.
    Please assign it to me.

  3. Stewartsson commented on Jul 1, 2026

    @Stewartsson
    Contributor

    /assign

  4. Bhavy12-cell commented on Jul 2, 2026

    @Bhavy12-cell
    Contributor

    Hi @Priyanshu-byte-coder
    Please assign me this issue.

  5. github-actions commented on Jul 2, 2026

    @github-actions

    Assigned to @Bhavy12-cell! You have 7 days to open a PR. No PR after 7 days = auto-unassigned so others can pick it up. Good luck!

  6. github-actions commented on Jul 13, 2026

    @github-actions

    ✅ Closed as completed!

    If DevTrack has been useful, a ⭐ star on the repo helps the project grow and reach more developers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions