T09 · Insecure Skill Coding Practices
- Location
scripts/batch.js:16- Finding
OS Command Injection Through Unsanitized NEAR CLI Arguments
- Content
View full analysis
Vulnerability Details
File Location:
scripts/batch.js:16-17andscripts/batch.js:39-40
Vulnerability Type: OS command injection
Risk Level: HighVulnerable Code
js const cmd = `near send ${senderAccount} ${recipient.account} ${recipient.amount}`; await execAsync(cmd);js const cmd = `near call ${transfer.contract} nft_transfer '{"receiver_id":"${transfer.receiver}","token_id":"${transfer.token_id}"}' --accountId ${senderAccount}`; await execAsync(cmd);Technical Analysis
The Skill constructs shell command strings by directly interpolating values originating from command-line arguments and user-supplied JSON files. It then executes those strings with
child_process.exec, which launches a shell.The affected untrusted values include:
senderAccount, supplied as a command-line argument.recipient.accountandrecipient.amount, read from the batch-send JSON file.transfer.contract,transfer.receiver, andtransfer.token_id, read from the NFT-transfer JSON file.
These values are not validated, escaped, or passed as isolated process arguments. An attacker who can influence the CLI invocation or batch file can include shell metacharacters or command substitutions in a field. The shell can interpret that content as additional commands rather than as a literal NEAR CLI argument.
The quoted JSON argument in the NFT command does not provide adequate protection. Interpolated values can disrupt the surrounding shell quoting and introduce additional shell syntax.
Attack Path
- An attacker creates or modifies a recipients or NFT transfers JSON file, or influences the
senderAccountcommand-line argument. - The attacker places shell syntax in an affected field, such as an account or contract value containing a command separator followed by another command.
- The victim invokes the Skill with
sendornft. - The Skill reads the attacker-controlled val ...[truncated 846 chars]
- Remediation
View remediation
Remediation Suggestions
-
Replace
child_process.execwithexecFileorspawn, using a fixed executable name and a separate argument array. This prevents the shell from interpreting user-controlled metacharacters.js const { execFile } = require('child_process'); const { promisify } = require('util'); const execFileAsync = promisify(execFile); await execFileAsync('near', [ 'send', senderAccount, recipient.account, String(recipient.amount) ]); -
Apply the same argument-array approach to NFT transfers. Serialize the contract-call payload with
JSON.stringifyinstead of manually constructing JSON inside a shell command.js const payload = JSON.stringify({ receiver_id: transfer.receiver, token_id: transfer.token_id }); await execFileAsync('near', [ 'call', transfer.contract, 'nft_transfer', payload, '--accountId', senderAccount ]); -
Strictly validate all NEAR account and contract identifiers against the accepted NEAR account-ID syntax before execution.
-
Validate amounts as finite, positive decimal values within an explicitly defined range. Reject exponential notation, signs, whitespace, and unexpected characters if they are not required.
-
Validate the complete JSON schema before processing:
- Require
recipientsortransfersto be an array. - Require every expected property to have the correct type.
- Reject unknown, missing, empty, or excessively long values.
- Limit the maximum number of batch operations.
- Require
-
Do not attempt to repair the existing design solely through shell escaping. Avoiding shell execution is more reliable and should be the primary control.
-
Run the Skill under a least-privileged account and protect local NEAR credentials with restrictive filesystem permissions. Consider requiring explicit confirmation before executing each b ...[truncated 27 chars]
-
