T09 · Insecure Skill Coding Practices
- Location
references/mcp-tools.md:47- Finding
Conflicting MCP Schemas Can Produce Incorrect Staking Transactions
- Content
View full analysis
Vulnerability Details
File Location:
references/mcp-tools.md:47-91,sub-skills/staking-manage.md:11-120,sub-skills/staking-rewards.md:12-25, andsub-skills/staking-query.md:55-67
Vulnerability Type: Inconsistent financial transaction schemas and token-unit handling
Risk Level: MediumVulnerable Documentation
The authoritative MCP reference defines the opening operation as requiring a Cardano address and an amount expressed as a string in the token's smallest unit:
markdown ### open_staking_position Open a new INDY staking position by locking INDY tokens. | Name | Type | Required | Description | |------|------|----------|-------------| | `address` | `string` | Yes | User Cardano bech32 address | | `amount` | `string` | Yes | Amount of INDY to stake (smallest unit) |However, the management workflow omits the required address, changes the amount type to a number, and treats the value as whole INDY:
markdown ### open_staking_position Open a new INDY staking position by locking INDY tokens. Staked INDY earns ADA rewards from protocol fees and grants governance voting power proportional to the staked amount. **Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `amount` | number | Yes | Amount of INDY to stake | **Returns:** Transaction CBOR to be signed and submitted. **Example — Stake 1000 INDY:**User: "Open a new staking position with 1000 INDY"
Tool call: open_staking_position({ amount: 1000 })
text Similar conflicts affect position adjustment. The MCP reference requires a caller address and explicit UTxO coordinates:
markdown ### adjust_staking_position Adjust an existing staking position — add or remove staked INDY. | Name | Type | Required | Description | |------|------|----------|-------------| | `address` | `string` | Yes | User Cardano bech32 address | | `stakingTxHash` | `string` | Yes | Staking position UTxO transaction hash | | `sta ...[truncated 5882 chars]- Remediation
View remediation
Remediation Suggestions
- Establish one authoritative, machine-readable MCP schema and generate all reference tables and examples from it.
- Use identical parameter names, types, and meanings in every file:
- Define whether
addressis the caller's wallet address or the staking-position address. - Require
stakingTxHashandstakingOutputIndexconsistently when UTxO coordinates are needed. - Use either
ownerorowners, with one consistent type. - Define whether reward distribution requires a caller address.
- Define whether
- Represent financial quantities as decimal strings rather than floating-point numbers.
- State the unit in every amount field and example. If the MCP endpoint expects smallest units, convert explicitly:
1 INDY = 1,000,000smallest units.1,000 INDY = "1000000000"smallest units.
- Before returning CBOR for signing, independently decode and validate the transaction. Display:
- Network identifier.
- Inputs and selected staking UTxO.
- All outputs and recipient addresses.
- INDY amount in both whole tokens and smallest units.
- ADA rewards, deposits, and network fee.
- Resulting total stake or withdrawal amount.
- Require explicit user confirmation of the normalized amount, selected position, outputs, and fee before presenting the transaction for signing.
- Reject ambiguous requests when a user owns multiple staking positions rather than selecting a position automatically.
- Add contract tests that execute every documented example against the actual MCP schema and fail on missing fields, incorrect parameter names, or denomination mismatches.
- Add boundary tests for zero, negative, fractional, minimum, and maximum amounts, along with Cardano network and address validation.
- Update all workflow documents together whenever the MCP interface changes to prevent schema drift.
