-
Notifications
You must be signed in to change notification settings - Fork 13
Security: Backstage identity JWT may leak to external GitHub host in CI activity proxy #218
Description
Summary
In plugins/catalog-backend-module-rhaap/src/router.ts, the handleGitHubCIActivity function currently falls back to forwarding the incoming Authorization header to the upstream GitHub API when no integration token is configured:
const tokenFromRequest = request.headers.authorization?.replace(/^Bearer\s+/i, '');
const { token: tokenFromConfig } = getGitHubIntegrationForHost(config, host);
const token = tokenFromConfig || tokenFromRequest;Backstage's fetchApi automatically injects the Backstage identity JWT (not a GitHub PAT) into Authorization: Bearer <backstage-jwt> on every outbound request. When tokenFromConfig is absent, this code strips the Bearer prefix and forwards that internal Backstage JWT to api.github.com (or any configured GitHub Enterprise host). GitHub will reject it, but the internal token is still sent to an external host — constituting an internal token leak.
Recommended Fix
- Verify the caller via the existing
httpAuthservice (already available increateRouteroptions). - Use a dedicated upstream header (e.g.,
X-GitHub-Token) for the GitHub PAT instead of repurposingAuthorization.
// Verify caller is a legitimate Backstage user/service
await httpAuth.credentials(request as unknown as HttpAuthRequest, {
allow: ['user', 'service'],
});
// Use a dedicated header for the upstream GitHub token
const tokenFromRequest = request.headers['x-github-token'] as string | undefined;
const { token: tokenFromConfig, apiBaseUrl: apiBaseFromConfig } =
getGitHubIntegrationForHost(config, host);
const token = tokenFromConfig || tokenFromRequest;The frontend (RepositoriesCIActivityTab.tsx / useLatestCIActivity.ts) would need to be updated to send X-GitHub-Token instead of relying on the Backstage Authorization header for the GitHub PAT.