Security Finding: RPC-Fetched ABI Enables Positional Argument Reordering in Contract Calls
Subsystem: contract
Severity: High
Model: claude-sonnet-4.6 (default)
Finding ID: H060
Root Cause
contract.Client.from() and Client.fromWasmHash() fetch WASM from the configured RPC endpoint and derive the callable Spec from that remote blob. Dynamic client methods then call spec.funcArgsToScVals(method, args), which serializes arguments in the order declared by the fetched spec.
Soroban invoke-contract arguments are positional on-chain. Because the SDK does not verify that the fetched WASM/spec matches a locally trusted ABI, a malicious RPC can keep the same parameter names while changing their declaration order and thereby alter the signed invocation.
Relevant code paths:
src/contract/client.ts: Client.from(), fromWasmHash()
src/contract/spec.ts: funcArgsToScVals() uses spec-declared order for positional encoding
Attack Vector
- Application uses
contract.Client.from() pointing at an attacker-controlled or compromised RPC endpoint.
- The attacker returns forged WASM whose
contractspecv0 section defines a target method with the same parameter names but a different declaration order for two type-compatible parameters (e.g., two Address inputs).
- The application calls the method with a benign-looking object like
{ primary, backup }.
- The SDK encodes values into positional Soroban arguments following the forged ABI order.
- The user signs a transaction for the real contract and method name, but with attacker-chosen argument ordering — silently altering contract behavior.
PoC Code
PoC result: The serialized on-chain argument order decodes to [backup, primary] instead of [primary, backup], confirming the SDK trusted the forged RPC-fetched ABI ordering.
Recommendation
Do not treat RPC-fetched WASM/spec as an integrity source for user-facing method encoding. Prefer one of:
- Require a locally trusted spec/WASM for signing flows — callers must supply the spec they trust.
- Pin and verify an expected WASM hash or spec digest before using RPC-fetched metadata for argument encoding.
- Clearly separate dynamic RPC-derived clients from locally generated bindings and warn that dynamic clients inherit the RPC trust boundary.
At minimum, the SDK documentation for Client.from() and fromWasmHash() should explicitly warn that these methods are unsafe against malicious RPCs for same-typed argument layouts, and steer security-sensitive applications toward locally generated bindings (e.g., via stellar contract bindings typescript) or locally supplied specs.
Note: Locally generated bindings (via stellar contract bindings typescript) embed the spec locally and do not suffer from this vulnerability — they are the recommended safe alternative for production use.
Security Finding: RPC-Fetched ABI Enables Positional Argument Reordering in Contract Calls
Subsystem: contract
Severity: High
Model: claude-sonnet-4.6 (default)
Finding ID: H060
Root Cause
contract.Client.from()andClient.fromWasmHash()fetch WASM from the configured RPC endpoint and derive the callableSpecfrom that remote blob. Dynamic client methods then callspec.funcArgsToScVals(method, args), which serializes arguments in the order declared by the fetched spec.Soroban invoke-contract arguments are positional on-chain. Because the SDK does not verify that the fetched WASM/spec matches a locally trusted ABI, a malicious RPC can keep the same parameter names while changing their declaration order and thereby alter the signed invocation.
Relevant code paths:
src/contract/client.ts:Client.from(),fromWasmHash()src/contract/spec.ts:funcArgsToScVals()uses spec-declared order for positional encodingAttack Vector
contract.Client.from()pointing at an attacker-controlled or compromised RPC endpoint.contractspecv0section defines a target method with the same parameter names but a different declaration order for two type-compatible parameters (e.g., twoAddressinputs).{ primary, backup }.PoC Code
PoC result: The serialized on-chain argument order decodes to
[backup, primary]instead of[primary, backup], confirming the SDK trusted the forged RPC-fetched ABI ordering.Recommendation
Do not treat RPC-fetched WASM/spec as an integrity source for user-facing method encoding. Prefer one of:
At minimum, the SDK documentation for
Client.from()andfromWasmHash()should explicitly warn that these methods are unsafe against malicious RPCs for same-typed argument layouts, and steer security-sensitive applications toward locally generated bindings (e.g., viastellar contract bindings typescript) or locally supplied specs.Note: Locally generated bindings (via
stellar contract bindings typescript) embed the spec locally and do not suffer from this vulnerability — they are the recommended safe alternative for production use.