[Security]: Payment verification replay vulnerability allows reusing same Stellar transaction across multiple investments
Maintainers usually reply within 1 day
@Danitello123 is already working on this.
Since Oct 17, 2026.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 52/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- postgresql, typescript
- Domain
- backend-api-design, security
Research direction
Start with src/services/stellar/verify-payment.service.ts, especially the listed validation and transaction lookup sections, then inspect src/models/Transaction.model.ts and src/models/Investment.model.ts and their database migrations. Trace how a verified operation is linked to an investment and how conflicts are returned. Done means the sender wallet is checked, a payment operation cannot confirm multiple investments, and reuse returns 409 Conflict.
Written by the indexing model from the issue text.
Description
Summary
In src/services/stellar/verify-payment.service.ts, verifyPayment checks that an on-chain transaction exists in Horizon and matches amount and escrow destination. However, it does NOT enforce global uniqueness on (stellarTxHash, operationIndex) across all database investments, nor does it verify that the transaction's source account matches the investor's wallet.
Location
- File:
src/services/stellar/verify-payment.service.ts(Lines 151-200, Lines 284-323)
const linkedTransactions = await unitOfWork.findTransactionsByInvestmentIdForUpdate(
lockedInvestment.id
);
return (
operation.assetCode === this.config.usdcAssetCode &&
operation.assetIssuer === this.config.usdcAssetIssuer &&
operation.destination === this.config.escrowPublicKey &&
operation.amount !== null &&
amountsWithinDelta(operation.amount, expectedAmount, this.config.allowedAmountDelta)
);
Impact
- A user can make one 100 USDC payment on Stellar, and call
verifyPaymentfor multiple separate 100 USDC investment commitments using the same transaction hash. All investments becomeCONFIRMEDwhile the platform only received funds once (double-crediting exploit). - Any observer watching the Stellar blockchain for payments to the escrow address can submit other parties' transaction hashes to confirm their own investments.
Expected Behavior
(stellarTxHash, operationIndex)must have a unique constraint acrosstransactionsandinvestmentsso no payment can be credited more than once.- The payment operation's source account / sender address must match
lockedInvestment.investorWallet.
Recommended Fix
- Add a unique index on
(stellar_tx_hash, stellar_operation_index)in the transactions/investments tables. - Check
operation.source_account === investment.investorWalletduring payment validation.
Scope
src/services/stellar/verify-payment.service.ts(Lines 144-252, 284-323)src/models/Transaction.model.ts,src/models/Investment.model.ts
Acceptance Criteria
-
verifyPaymentvalidates thatoperation.source_accountmatches the investor's wallet address (lockedInvestment.investorWallet). - Database enforces a unique constraint on
(stellar_tx_hash, stellar_operation_index)across transactions and investments. - Calling
verifyPaymentwith a transaction hash/operation index that has already confirmed another investment returns409 Conflict.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 82
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 76
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from StellarState/SS-backend
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
StellarState/SS-backend#712 ·
Maintainers usually reply within 1 day
-
[Database]: Migration 1731900000001 fails because is_kyc_verified column already exists in InitialSchemaPossibly taken @emynogithub claimed this 6 days ago. Openbug domain: database priority: p1 Stellar Wave
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
StellarState/SS-backend#631 · 5 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
[Bug]: KYC document submission endpoints incorrectly require seller role, blocking investors from KYCPossibly taken @Stephan-Thomas claimed this 6 days ago. Openbug domain: backend priority: p1 Stellar Wave
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
StellarState/SS-backend#626 · 6 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
[Bug]: Non-functional stub in /invoices/publish returns success without publishing the invoicePossibly taken @emynogithub claimed this 6 days ago. Openbug domain: backend priority: p1 Stellar Wave
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
StellarState/SS-backend#625 · 4 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
[Bug]: Horizon health probe reads undefined HORIZON_URL instead of STELLAR_HORIZON_URL in app.tsPossibly taken @Danitello123 claimed this 6 days ago. Openbug domain: backend priority: p2 Stellar Wave
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
StellarState/SS-backend#614 · 4 comments · 1 assignee ·
Maintainers usually reply within 1 day
All issues in StellarState/SS-backend
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Nimblesite/SharpLsp#468 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Bundled uv is never updated and trusts the compromised eMudhra certificatesPossibly taken @FabienDanieau claimed this today. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
bg_wait's blocking mode (stopOnAttention: false) is under-documented and effectively undiscoverableOpen
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
nicobailon/pi-subagents#3019 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
db-ux-design-system/core-web#8613 ·
Maintainers usually reply within 1 day