fix: eliminate push-mode semaphore exhaustion issue#44
Merged
marcelosalloum merged 4 commits intomainfrom Apr 20, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens the Stellar charge server’s push-mode verification path against semaphore-exhaustion DoS by removing polling behavior for client-submitted transaction hashes and adding stricter hash validation at the schema layer.
Changes:
- Replace push-mode
pollTransactionusage with a singlerpcServer.getTransaction()lookup and fail fast onNOT_FOUND/FAILED. - Add Zod schema regex validation for
credential.payload.hash(/^[0-9a-f]{64}$/i). - Add/adjust tests to cover immediate rejection for
NOT_FOUND/FAILEDand concurrent fake-hash requests without semaphore contention.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| sdk/src/charge/server/Charge.ts | Removes push-mode polling and adds single-lookup status handling for hash verification. |
| sdk/src/charge/server/Charge.test.ts | Adds tests ensuring push-mode fast-failure and no semaphore contention. |
| sdk/src/charge/Methods.ts | Tightens schema validation for push-mode hash credentials. |
| sdk/src/charge/Methods.test.ts | Adds schema tests for valid/invalid hash formats. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
sagpatil
approved these changes
Apr 20, 2026
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.
What
pollTransactionloop with a singlegetTransactioncall for push-mode (hash) credentials — fake hashes are rejected instantly without acquiring a semaphore slot/^[0-9a-f]{64}$/i) to the hash field inMethods.ts, rejecting malformed hashes at the Zod layer before any server-side processingWhy
PR #42 replaced the global
verifyLockwith aSemaphore(10), but an attacker could still exhaust all semaphore slots by submitting format-valid fake hashes (e.g.deadbeefrepeated) that each held a slot for the fullpollTimeoutMs(20s). Ten requests every 20 seconds permanently blocks all push-mode verifications.This change removes polling from push mode entirely. A single
getTransactioncall returns instantly for non-existent hashes (NOT_FOUND), eliminating the attack vector. Pull-mode (transaction) polling and its semaphore are unchanged — the server controls those hashes.