Skip to content

core/cli: no argument-injection guard on method names, arg keys/values and --source before they reach the stellar CLI (assertSorobanSymbol is dead code) #136

Description

@Dione-b

Summary

Caatinga builds stellar argv arrays by hand and never checks that user/config-supplied tokens are not themselves flags. execa is used without a shell, so this is not shell injection — but it is argument injection into the Stellar CLI, and every affected path ends in a signed transaction.

Unvalidated values that land in argv positions:

Value Source Lands at
target.method ctg invoke <contract>.<method> after --, as the contract method name (invoke-contract.ts:63)
method arg keys --<key> in ctg invoke/read, deployArgs/postDeploy.args in config --${toSnakeCaseFlag(key)} (format-cli-args.ts:22)
method arg values same positional value right after the flag (format-cli-args.ts:22)
upgradeMethod / wasmArg UpgradeContractOptions -- <upgradeMethod> --<wasmArg> (upgrade-contract.ts:133-134)
source --source, CAATINGA_SOURCE stellar keys address <source> positional (resolve-source-address.ts:19) and --source-account <source>
hook.method postDeploy in caatinga.config.ts after -- (run-post-deploy.ts:203)

Two concrete gaps:

1. assertSorobanSymbol is dead code. packages/core/src/soroban/assert-soroban-symbol.ts implements exactly the right check (/^[A-Za-z0-9_]{1,32}$/), but grep shows its only non-test reference in the whole repo is the re-export in browser.ts:8. Neither parseInvokeTarget (invoke-target.ts:10-22, which only splits on .) nor run-post-deploy nor upgrade-contract calls it. Method names reach the CLI completely unchecked.

2. assertSafeSourceAccount doesn't reject flag-shaped aliases. validate-source-shape.ts rejects secret keys (S…), seed phrases (whitespace) and public keys (G…) — good — but a source of --config-dir or -h passes and is handed to stellar keys address <source> as a positional, where clap reads it as an option.

Failure scenario

ctg invoke counter."--some-flag" --network mainnet --source deployer (or a postDeploy entry whose args value is --other_param) produces:

stellar contract invoke --id C... --source-account deployer --network mainnet -- --some-flag ...

Everything after -- is parsed by the clap subcommand the Stellar CLI generates from the contract spec, so an attacker-influenced or typo'd value is interpreted as a different parameter of the same method rather than as the value of the intended one — silently changing what gets signed. The Stellar CLI also exposes --<arg>-file-path style options in that position, which widens the impact from "wrong argument" to "argument read from an arbitrary file".

The realistic threat model here is not a remote attacker: it is a config file, a CI variable, or an npm run script that someone else contributed. The point is that the coordination layer offers no validation between those inputs and a signed mainnet transaction.

Suggested fix

  • Call assertSorobanSymbol on target.method in parseInvokeTarget, on hook.method in run-post-deploy, and on upgradeMethod/wasmArg in upgrade-contract.
  • In formatNamedCliArgs, reject keys that don't match /^[A-Za-z_][A-Za-z0-9_]*$/ and values that start with -, or pass values as --key=value so a leading dash cannot be re-parsed as a flag.
  • Extend validateSourceShape to reject any source starting with -.

Note: validate-source-shape.ts:5 also rejects any alias starting with a capital S as a "secret key" — --source Staging is refused. Worth tightening to the full S[A-Z2-7]{55} strkey shape in the same pass.

Scope: audit was read-only, no code changed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Stellar WaveIssues in the Stellar wave programarea: contractsDeploy, upgrade, invoke, contract logicarea: validationRegex validation, input validationpriority: highHigh priority fix - data corruption, security, or recovery failure risk

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions