T09 · Insecure Skill Coding Practices
- Location
scripts/stake.mjs:96- Finding
Unvalidated Receiver Can Redirect Staking Assets
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill appears aimed at StakeWise staking, but it can submit real Ethereum mainnet transactions using a raw private key without adequate confirmation, validation, or safety warnings.
Review this carefully before installing. Use only a dedicated low-balance wallet, verify the vault, chain, amount, and receiver before every run, and avoid placing a valuable raw private key in the environment. Treat the staking command as a live Ethereum mainnet transaction that can spend funds and incur gas immediately.
scripts/stake.mjs:96Unvalidated Receiver Can Redirect Staking Assets
README.md:8Unpinned Wallet Runtime Dependency
The description presents a broader StakeWise staking skill with stake, unstake, position checking, and state update support. The supplied code chunk is strictly a read-only position checker: it uses ethers to call balanceOf, convertToAssets, and totalAssets on a hardcoded vault, using an address from environment variables. There are no write transactions, no stake/unstake methods, no signer usage beyond unused private key configuration, and no subgraph, keeper, or harvest proof logic. This is a material description-to-behavior mismatch because the implemented primary behavior is only one subset of the declared functionality.
The script submits an irreversible on-chain staking transaction immediately after computing parameters, with no human confirmation, simulation, or transaction summary. In a staking skill that moves real ETH, this is especially dangerous because a mistaken amount, wrong receiver address, stale subgraph data, or malicious invocation can cause immediate and non-recoverable fund commitment.
The README instructs users to export a raw Ethereum private key into an environment variable without any warning about secret handling, shell history, process exposure, or safer alternatives. In a skill that directly manages on-chain funds, this increases the chance of credential leakage and wallet compromise, which could result in total loss of assets.
The staking command is presented like a routine script invocation but does not explicitly warn that it will submit a live Ethereum mainnet transaction using the user's wallet and funds. In the context of a staking skill, this omission is dangerous because users may run the command without understanding that it can irreversibly transfer ETH, incur gas costs, and interact with protocol state fetched from external infrastructure.
The skill documents access to sensitive environment variables, including a raw private key, but does not declare any explicit tool scope or permission boundary. In an agent setting, missing scope metadata weakens reviewability and increases the chance the skill is invoked with broader access than users expect.
The documentation tells users to export a raw PRIVATE_KEY directly into the environment without explaining the sensitivity of that secret or safer alternatives. This increases the risk of credential theft through shell history, process inspection, logs, shared environments, or accidental disclosure to other tools in the agent runtime.
The skill instructs users to run staking and unstaking commands that can submit irreversible on-chain transactions spending ETH or burning osETH, but it omits a clear warning about financial risk, finality, gas costs, and recipient/address validation. In an agent or automation context, users may execute these commands without appreciating that real funds will be moved immediately.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
};
const response = await fetch('https://graphs.stakewise.io/mainnet-a/subgraphs/name/stakewise/prod', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subgraphQuery)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
};
const response = await fetch('https://graphs.stakewise.io/mainnet-a/subgraphs/name/stakewise/prod', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subgraphQuery)
The script directly consumes a private key from the environment and constructs a signing wallet without any explicit safety notice, secure key handling guidance, or protective controls. In an agent skill context that performs financial actions, this increases the chance that users supply hot-wallet credentials to automation they may not fully understand, leading to accidental exposure or misuse of signing authority.
The manifest describes a broader skill scope including unstaking ETH and checking staked positions on StakeWise V3 vaults. In this file, the only implemented operation is stakeETH, which performs a deposit transaction; there is no code for withdrawal/unstake flows or for querying and returning position data beyond an internal state-update check.
The inline comment states 'Simple deposit if no state update needed' and the log says 'using simple deposit', which communicates that the branch performs a deposit flow. In reality, the branch is unimplemented and immediately throws an error claiming state update is always required, directly contradicting the documented intent of that block.
No suspicious patterns detected.