Filed from PR #102 review thread (Ludo inline #102 (comment)).
Scope
The Lua SDK ships a regression test at `lua/tests/solana_verify_spec.lua:786` titled "SECURITY: rejects extra SystemProgram transfer sourced from fee-payer on SPL route". That test guards a real attack pattern that every SDK must enforce. Write the invariant up as cross-SDK security documentation so any future language port has a reference.
Attack shape
- Server advertises a server-side fee-payer (`methodDetails.feePayer = true`).
- Client builds a valid SPL token-transfer payment to the recipient.
- Client appends an extra `SystemProgram::Transfer` instruction sourced from the fee-payer to an attacker-controlled wallet.
- Without a source-pubkey allowlist guard the server co-signs the transaction (the SPL transfer half is valid for the receipt) and the fee-payer SOL drain settles in the same tx.
The guard required: server verifier MUST allowlist `SystemProgram::Transfer` source pubkeys. Specifically: when fee_payer mode is active, any SystemProgram transfer in the verified tx must NOT be sourced from the fee-payer's pubkey unless it is the explicit payment instruction (which for the SPL route never is).
Where the guard lives today
- Rust spine: `rust/src/server/charge.rs` (canonical implementation; trace the SystemProgram transfer guard).
- Lua: `lua/mpp/server/solana_verify.lua` (mirrored guard + the cited regression test in `solana_verify_spec.lua:786`).
- Python: attack regression set under `python/tests/`.
- TypeScript: `typescript/packages/mpp/src/server/Charge.ts` instruction allowlist + source-pubkey check.
- PHP: `php/src/Server/SolanaChargeTransactionVerifier.php` instruction allowlist.
- Ruby: `ruby/lib/mpp/methods/solana/verifier.rb`.
- Go: `go/server/` verifier.
Proposal
- Create `docs/security/fee-payer-drain.md` (or wherever the repo's security docs land) that:
- Names the attack.
- Shows the malicious instruction sequence.
- Lists the server-side guard each SDK must implement.
- Points to the regression test in each language so a new SDK port has a reference.
- Add a cross-SDK interop scenario under `tests/interop/` (analogous to charge-cross-server-portability) that asserts every server REJECTS the attack tx with a canonical error code.
- Add the doc to the contributor onboarding so any new method-handler port has a checklist item.
Label as `m2-followup` / cross-SDK invariant work.
Filed from PR #102 review thread (Ludo inline #102 (comment)).
Scope
The Lua SDK ships a regression test at `lua/tests/solana_verify_spec.lua:786` titled "SECURITY: rejects extra SystemProgram transfer sourced from fee-payer on SPL route". That test guards a real attack pattern that every SDK must enforce. Write the invariant up as cross-SDK security documentation so any future language port has a reference.
Attack shape
The guard required: server verifier MUST allowlist `SystemProgram::Transfer` source pubkeys. Specifically: when fee_payer mode is active, any SystemProgram transfer in the verified tx must NOT be sourced from the fee-payer's pubkey unless it is the explicit payment instruction (which for the SPL route never is).
Where the guard lives today
Proposal
Label as `m2-followup` / cross-SDK invariant work.