What happened?
The "Claim" button on the Browse Issues page (claimIssue in src/app/actions/issues.ts) does not enforce the 3-active-claims limit, unlike its twin action claimRecommendation in src/app/actions/recommendations.ts.
claimRecommendation enforces the rule with a pre-check + post-commit rollback:
// recommendations.ts:119-127
const { count: preCount } = await service
.from('recommendations')
.select('id', { count: 'exact', head: true })
.eq('user_id', user.id)
.eq('status', 'claimed')
.gte('expires_at', now);
if ((preCount ?? 0) >= 3) {
return err('claim_limit', 'you already have 3 active claims - merge or close them first');
}
claimIssue performs no such count — it only checks that the user hasn't already claimed this specific issue (issues.ts:329-350), then inserts a status: 'claimed' row unconditionally:
// issues.ts:354-367
const { data: inserted } = await service
.from('recommendations')
.insert({ ... status: 'claimed', claimed_at: now })
.select('id').single();
Both paths write to the same recommendations table with status: 'claimed', so a user can claim unlimited distinct issues via the issues page, bypassing the 3-active-claim rule entirely.
Steps to Reproduce
- Sign in with a fresh account and install the GitHub App.
- Open
/issues and click "Claim" on 4+ different issues.
- All four claims succeed — the dashboard then shows 4+ active claims.
- Attempt to claim a recommended issue from the dashboard: blocked by
claim_limit.
Expected Behavior
claimIssue should count the user's active (non-expired, status = 'claimed') recommendations and reject when >= 3, mirroring claimRecommendation. It should also apply the same atomic post-claim verification/rollback so concurrent requests can't slip past the limit.
Where does this occur?
Contributor Dashboard
Environment
Not environment-specific — logic bug reproducible in any deployment.
Related
What happened?
The "Claim" button on the Browse Issues page (
claimIssueinsrc/app/actions/issues.ts) does not enforce the 3-active-claims limit, unlike its twin actionclaimRecommendationinsrc/app/actions/recommendations.ts.claimRecommendationenforces the rule with a pre-check + post-commit rollback:claimIssueperforms no such count — it only checks that the user hasn't already claimed this specific issue (issues.ts:329-350), then inserts astatus: 'claimed'row unconditionally:Both paths write to the same
recommendationstable withstatus: 'claimed', so a user can claim unlimited distinct issues via the issues page, bypassing the 3-active-claim rule entirely.Steps to Reproduce
/issuesand click "Claim" on 4+ different issues.claim_limit.Expected Behavior
claimIssueshould count the user's active (non-expired,status = 'claimed') recommendations and reject when>= 3, mirroringclaimRecommendation. It should also apply the same atomic post-claim verification/rollback so concurrent requests can't slip past the limit.Where does this occur?
Contributor Dashboard
Environment
Not environment-specific — logic bug reproducible in any deployment.
Related
claimRecommendation, but the limit is still bypassable through the unguardedclaimIssuepath.