fix: forbid cross-user balance deduction in billing deduct route - #1377
Open
FreshTVMax wants to merge 2 commits into
Open
FreshTVMax wants to merge 2 commits into
FreshTVMax wants to merge 2 commits into
Conversation
|
@FreshTVMax Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
Thanks for the contribution! We reviewed this PR while merging the open queue and couldn't merge it yet. Here's what needs fixing:
Once these are fixed, push to this branch and we'll take another look. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR closes a direct theft vector in
POST /api/billing/deduct: the endpoint previously accepted an optionaldeveloperIdin the request body and forwarded it as theuserIdtoBillingService.deduct, letting any authenticated caller drain another user's Soroban balance. The fix enforces that the deduction target must match the authenticated caller unless the caller is an admin (viaadminAuth) or a service principal holding an explicit billing scope, and audit-logs every rejected cross-user attempt.Related Issue
Changes
🔒 Deduction Authorization
[MODIFY]
src/middleware/requireAuth.tsres.locals.authenticatedUser(id + role/scope metadata) so downstream handlers can compare the request body'sdeveloperIdagainst the caller identity.x-user-idfallback behavior for backward compatibility while ensuring the resolved identity is what the deduct route authorizes against.[MODIFY]
src/middleware/adminAuth.tsres.localsso the deduct route can distinguish privileged callers from ordinary users.🧪 Tests
[MODIFY]
src/routes/billing/deduct.test.tsdeveloperIdreturns 403 andBillingService.deduct/ Soroban is never invoked.developerIdstill deducts from the authenticated caller.developerIdstill succeeds.[MODIFY]
tests/integration/billing-http.test.tsdeveloperId), and the privileged admin/service path.[MODIFY]
src/__tests__/billingDeductMetrics.test.tsVerification Results
developerIdof another user returns 403 and does not call Sorobandeduct.ts; asserted in unit + integration testsdeveloperIdor matching the caller still worksadminAuthexposes scope; route permits privileged callerslogger.auditinvoked on rejection with actor + targetSecurity and Failure-Mode Handling
developerId.BillingService.deductis invoked, so no on-chain or balance mutation occurs.logger.auditwith both the authenticated actor and the requested target, supporting incident response.developerIdor pass their own id are unaffected; only cross-user deductions by unprivileged callers change behavior.Closes #1252