Back to skill

Security audit

Morpho Earn - earn safe yield on your USDC on Base

Security checks for vulnerabilities and agentic risk

Overview

This skill is for DeFi yield automation, but it can create recurring real-money wallet transactions with weak safeguards.

Install only with a dedicated low-balance hot wallet. Do not enable auto-compound or HEARTBEAT.md automation until there are explicit transaction caps, confirmation prompts, and stricter Odos transaction validation. Review the configured wallet address before every write operation, avoid broad allowances, and prefer pinned dependencies and safer secret handling.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/compound.ts:198
Finding
Untrusted Odos API Transactions Are Signed Without Sufficient Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/compound.ts:198-221, 383-407`; `scripts/test-swap.ts:89-110, 166-188` **Vulnerability Type**: Arbitrary transaction signing from an untrusted remote response **Risk Level**: High ### Vulnerable Code ```ts async function assembleOdosTransaction( pathId: string, userAddress: Address ): Promise<OdosAssembleResponse | null> { const response = await rateLimitedFetch('https://api.odos.xyz/sor/assemble', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userAddr: userAddress, pathId, simulate: false, }), }); if (!response.ok) { console.log(` ⚠️ Odos assemble failed: ${response.status}`); return null; } const data = await response.json() as OdosAssembleResponse; if (!data.transaction?.to || !data.transaction?.data) { console.log(` ⚠️ Invalid Odos assemble response`); return null; } return data; } ``` ```ts const assembled = await assembleOdosTransaction(quote.pathId, account.address); if (!assembled) { console.log(` ⚠️ Could not assemble transaction, skipping ${token.symbol}\n`); continue; } const gasEstimate = BigInt(assembled.transaction.gas); const gasWithBuffer = gasEstimate + (gasEstimate * 50n / 100n); const nonce = await getFreshNonce(publicClient, account.address); const swapHash = await walletClient.sendTransaction({ to: assembled.transaction.to as Address, data: assembled.transaction.data as Hex, value: BigInt(assembled.transaction.value), gas: gasWithBuffer, nonce, }); ``` ### Technical Analysis The Odos assembly API controls the transaction destination, calldata, native token value, and gas estimate. Validation only verifies that the `to` and `data` properties exist. The implementation does not: - Require `transaction.to` to equal the known `ODOS_ROUTER`. - Decode and validate the returned calldata. - Verify the input token, input amount, output token, recip ...[truncated 1499 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require the returned destination to exactly match the verified Odos router address for Base. 2. Reject nonzero native value unless it is explicitly required and bounded by the operation. 3. Decode the calldata and verify: - Function selector. - Input token and exact maximum input amount. - Output token. - Recipient. - Minimum output. - Deadline. 4. Simulate the complete assembled transaction locally using the configured RPC before signing. 5. Compare the assembly response against the original quote and reject inconsistent values. 6. Enforce balance-delta checks after execution. 7. Require explicit confirmation for material swaps and establish configurable per-transaction and daily limits. 8. Consider constructing the router call locally rather than signing opaque API-provided calldata. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/compound.ts:436
Finding
Auto-Compound Deposits the Wallet's Entire USDC Balance<![CDATA[ ## Vulnerability Details **File Location**: `scripts/compound.ts:436-477` **Vulnerability Type**: Overbroad asset authority and failure to isolate reward proceeds **Risk Level**: High ### Vulnerable Code ```ts const usdcBalance = await getTokenBalance( publicClient, USDC_ADDRESS, account.address ); if (usdcBalance === 0n) { console.log('No USDC available to deposit.'); console.log('\n✅ Compound complete (no USDC to deposit)'); return; } console.log(`USDC available: ${formatUSDC(usdcBalance)} USDC`); const vaultAllowance = await publicClient.readContract({ address: USDC_ADDRESS, abi: ERC20_ABI, functionName: 'allowance', args: [account.address, VAULT_ADDRESS], }); if (vaultAllowance < usdcBalance) { await approveAndVerify( publicClient, walletClient, account, USDC_ADDRESS, VAULT_ADDRESS, usdcBalance, 'USDC' ); } const depositHash = await simulateAndWrite(publicClient, walletClient, { address: VAULT_ADDRESS, abi: VAULT_ABI, functionName: 'deposit', args: [usdcBalance, account.address], account, }); ``` ### Technical Analysis The declared auto-compound operation is intended to claim rewards, convert those rewards to USDC, and reinvest the resulting USDC. However, the script does not calculate the amount generated by reward swaps. Instead, it reads the wallet's final USDC balance and deposits that entire balance. This includes unrelated USDC that existed before compounding or arrived from another source. The resulting approval and deposit authority therefore exceed the minimum privileges needed to reinvest rewards. ### Attack Path 1. The configured wallet holds USDC unrelated to Morpho rewards, such as reserved funds or a recent transfer. 2. A user or recurring heartbeat invokes `compound.ts`. 3. The script claims and swaps rewards, if any. 4. The script reads the wallet's complete USDC balance. 5. It approves the vault for that balance when required. 6. It deposits all available US ...[truncated 547 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Record the wallet's USDC balance before claiming or swapping rewards. 2. Deposit only the positive balance delta attributable to the compound operation. 3. Track each swap's verified output and use the smaller of the verified output total and the measured balance delta. 4. Introduce configurable per-run and daily deposit caps. 5. Preserve a configurable minimum wallet USDC reserve. 6. Require explicit user confirmation before depositing any pre-existing USDC. 7. Abort if the measured balance delta materially differs from the expected swap output. 8. Clearly display the reward-derived deposit amount separately from the wallet's total balance. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup.ts:207
Finding
Setup Defaults to Persistent Unattended Real-Fund Execution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.ts:92-118, 207-208, 223-251` **Vulnerability Type**: Unsafe default authorization for recurring financial transactions **Risk Level**: High ### Vulnerable Code ```ts if (prefs.autoCompound) { entry += ` - Run \`npx tsx compound.ts\` to claim and reinvest\n`; entry += ` - Send a report to the user after compounding\n`; } else { entry += ` - Notify user that rewards are ready to compound\n`; } ``` ```ts const autoInput = await ask( rl, 'Auto-compound when threshold reached? [Y/n]: ' ); const autoCompound = autoInput.toLowerCase() !== 'n'; ``` ```ts const addToHeartbeat = await ask( rl, 'Add to HEARTBEAT.md automatically? [Y/n]: ' ); if (addToHeartbeat.toLowerCase() !== 'n') { const heartbeatPath = path.join( process.env.HOME || '~', 'clawd', 'HEARTBEAT.md' ); if (fs.existsSync(heartbeatPath)) { let content = fs.readFileSync(heartbeatPath, 'utf-8'); content = content.replace( /\n## Morpho Yield[\s\S]*?(?=\n## |$)/, '' ); content = content.trimEnd() + '\n' + heartbeatEntry; fs.writeFileSync(heartbeatPath, content); console.log('✅ Added to HEARTBEAT.md\n'); } } ``` ### Technical Analysis Pressing Enter at both setup prompts enables auto-compounding and writes recurring instructions into the agent's persistent `HEARTBEAT.md` file. Those instructions direct future agent runs to execute `compound.ts`, which can claim rewards, approve tokens, sign API-assembled swaps, and deposit USDC. The persistence is disclosed to the user and is related to declared functionality, so it is not classified as covert memory poisoning. Nevertheless, default-on recurring financial authority is unsafe. The setup flow does not require strong, explicit consent, transaction caps, a confirmation policy, or scoped signing authority. ### Attack Path 1. A user runs setup and accepts the displayed defaults by pressing Enter. 2. `autoCompound` bec ...[truncated 813 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default auto-compounding to “No.” 2. Default modification of `HEARTBEAT.md` to “No.” 3. Require explicit typed consent that describes every permitted transaction type. 4. Separate read-only monitoring from transaction execution. 5. Require per-run confirmation unless the user deliberately enables a constrained automation mode. 6. Add maximum swap, approval, deposit, gas, and daily loss limits. 7. Use exact-amount approvals and revoke residual allowances where practical. 8. Provide a simple command to disable automation and remove the heartbeat entry. 9. Prefer scoped smart accounts or session keys that can interact only with verified contracts and bounded amounts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.ts:299
Finding
1Password Configuration Can Inject Shell Commands<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.ts:299-305` **Vulnerability Type**: OS command injection **Risk Level**: Medium ### Vulnerable Code ```ts case '1password': { const item = wallet.item || 'Morpho Bot Wallet'; const field = wallet.field || 'private_key'; try { key = execSync( `op read "op://${item}/${field}"`, { encoding: 'utf-8' } ).trim(); } catch { console.error( '❌ Failed to read from 1Password. Is the CLI installed and authenticated?' ); console.error(' Run: op signin'); process.exit(1); } break; } ``` ### Technical Analysis The `wallet.item` and `wallet.field` values originate from the JSON configuration and are interpolated into a command string executed through a shell. Although the interactive setup sanitizes newly entered item names, `loadConfig()` does not apply a strict runtime schema to manually created or subsequently modified configuration. The `field` property is not sanitized in the shown runtime path. Quotation marks, command substitutions, or shell metacharacters can therefore terminate or alter the intended command. File-permission warnings do not eliminate the vulnerability because configuration may be changed through another compromised local process, unsafe deployment mechanism, backup restoration, or manual editing. ### Attack Path 1. An attacker or compromised process gains the ability to modify `~/.config/morpho-yield/config.json`. 2. The attacker selects the `1password` source and places shell syntax in `wallet.item` or `wallet.field`. 3. The user or agent runs any command that calls `getClients()`. 4. `getPrivateKey()` builds the `op read` command using the malicious values. 5. `execSync()` invokes a shell and executes the injected command with the privileges of the agent process. ### Impact Assessment Successful exploitation provides arbitrary local command execution as the user running the Skill. This can expose local files and crede ...[truncated 246 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace shell-string execution with argument-based process execution: ```ts execFileSync('op', ['read', `op://${item}/${field}`], { encoding: 'utf-8', shell: false, }); ``` 2. Validate the entire loaded configuration against a strict schema. 3. Restrict item and field values to the documented 1Password reference grammar. 4. Reject quotation marks, control characters, command substitutions, and shell metacharacters. 5. Fail closed when the configuration file has unsafe ownership or permissions rather than merely warning. 6. Avoid including sensitive command output in thrown errors or logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.ts:163
Finding
Environment Wallet Configuration Uses Inconsistent Property Names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.ts:163-169`; `scripts/config.ts:291-296` **Vulnerability Type**: Configuration confusion causing unintended wallet selection **Risk Level**: Medium ### Vulnerable Code ```ts if (walletChoice === '2') { const envVar = await ask( rl, 'Environment variable name [MORPHO_PRIVATE_KEY]: ' ); const sanitizedEnv = sanitizeEnvVar(envVar) || 'MORPHO_PRIVATE_KEY'; config.wallet = { source: 'env', env: sanitizedEnv, }; } ``` ```ts case 'env': { key = process.env[ wallet.env_var || 'MORPHO_PRIVATE_KEY' ]; if (!key) { console.error( `❌ Environment variable ${ wallet.env_var || 'MORPHO_PRIVATE_KEY' } not set` ); process.exit(1); } break; } ``` ### Technical Analysis The setup program writes the selected environment variable name to `wallet.env`, while runtime key loading reads `wallet.env_var`. As a result, any custom environment variable configured through setup is ignored. Runtime silently falls back to `MORPHO_PRIVATE_KEY`. If that variable is present and contains a different wallet's key, subsequent operations use the unintended wallet rather than failing safely. The TypeScript interfaces are also inconsistent: the setup-side interface declares `env`, while the runtime-side interface declares `env_var`, preventing the type system from detecting the cross-file mismatch. ### Attack Path 1. The user selects a custom environment variable during setup. 2. Setup writes that name as the `env` property. 3. A different `MORPHO_PRIVATE_KEY` is already available in the agent environment. 4. A deposit, withdrawal, reward, report, or compound script loads the configuration. 5. Runtime ignores `env` and loads the fallback key. 6. The script displays and operates on the wallet derived from the fallback key. 7. If the displayed address is not carefully reviewed, transactions are executed from the wrong wallet. ### Impact Assessment The defe ...[truncated 298 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Standardize on one property name, such as `env_var`, in all interfaces, documentation, setup code, and runtime code. 2. Define and import a single shared configuration schema. 3. Reject unknown properties and require the selected environment variable to exist. 4. Do not silently fall back when the configuration explicitly selects a custom variable. 5. Display the derived wallet address and require explicit confirmation before enabling write operations. 6. Add tests covering every wallet source and custom property value. 7. Migrate existing configurations that use the obsolete `env` property. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/deposit.ts:96
Finding
Transaction Previews Do Not Require User Confirmation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deposit.ts:96-143`; `scripts/withdraw.ts:141-166`; `scripts/test-swap.ts:286-310` **Vulnerability Type**: Irreversible financial operations execute immediately after informational previews **Risk Level**: Medium ### Vulnerable Code ```ts console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.log('📋 Transaction Preview'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.log(`Depositing: ${formatUSDC(depositAmount)} USDC`); console.log(`Expected shares: ${formatUSDC(expectedShares)} mwUSDC`); console.log(`USDC after: ${formatUSDC(usdcBalance - depositAmount)} USDC`); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); const currentAllowance = await publicClient.readContract({ address: USDC_ADDRESS, abi: ERC20_ABI, functionName: 'allowance', args: [account.address, VAULT_ADDRESS], }); if (currentAllowance < depositAmount) { const approveHash = await approveAndVerify( publicClient, walletClient, account, USDC_ADDRESS, VAULT_ADDRESS, depositAmount, 'USDC' ); } const depositHash = await simulateAndWrite(publicClient, walletClient, { address: VAULT_ADDRESS, abi: VAULT_ABI, functionName: 'deposit', args: [depositAmount, account.address], account, }); ``` The test utility similarly prints a plan and then immediately performs real swaps: ```ts console.log(`📋 Test Swap Plan`); console.log(`Swapping ${formatUSDC(halfAmount)} USDC → WELL`); console.log(`Swapping ${formatUSDC(halfAmount)} USDC → MORPHO`); const wellSuccess = await swapToken( publicClient, walletClient, account, USDC_ADDRESS, 'USDC', halfAmount, WELL_ADDRESS, 'WELL' ); const morphoSuccess = await swapToken( publicClient, walletClient, account, USDC_ADDRESS, 'USDC', halfAmount, MORPHO_ADDRESS, 'MORPHO' ); ``` ### Technical Analysis The scripts describe output as a transaction preview, but the preview is info ...[truncated 1389 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require an interactive confirmation immediately before signing each transaction. 2. Display the chain, signer, contract, function, recipient, token, amount, allowance, expected output, slippage, value, and estimated gas. 3. Require a deliberate phrase such as `CONFIRM 100 USDC` for high-value operations. 4. Support noninteractive execution only through an explicit `--yes` or automation flag. 5. Apply configurable per-operation and daily limits in automation mode. 6. Rename `test-swap.ts` to clearly indicate that it uses real funds, or make it dry-run-only by default. 7. Enforce the documented test amount cap unless the user supplies an additional explicit override. 8. Ensure reward claims and externally assembled swap transactions use the same simulation and confirmation policy. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (126)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Token swaps via Odos and corresponding ERC-20 approvals introduce materially different risk than simple vault deposits because they depend on third-party routing logic, external quote/assembly APIs, and broader token permissions. In a wallet-managing skill, undeclared swap behavior can lead to unintended approvals or asset movement if users assume the skill only touches USDC and the vault.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Token swaps via Odos and corresponding ERC-20 approvals introduce materially different risk than simple vault deposits because they depend on third-party routing logic, external quote/assembly APIs, and broader token permissions. In a wallet-managing skill, undeclared swap behavior can lead to unintended approvals or asset movement if users assume the skill only touches USDC and the vault.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Token swaps via Odos and corresponding ERC-20 approvals introduce materially different risk than simple vault deposits because they depend on third-party routing logic, external quote/assembly APIs, and broader token permissions. In a wallet-managing skill, undeclared swap behavior can lead to unintended approvals or asset movement if users assume the skill only touches USDC and the vault.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Token swaps via Odos and corresponding ERC-20 approvals introduce materially different risk than simple vault deposits because they depend on third-party routing logic, external quote/assembly APIs, and broader token permissions. In a wallet-managing skill, undeclared swap behavior can lead to unintended approvals or asset movement if users assume the skill only touches USDC and the vault.

Ae1

High
Category
analysis-evasion
Content
Rewards update approximately every 8 hours. The `compound.ts` script handles:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Known Vulnerable Dependency: ws==8.18.3 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding
The lockfile pins transitive dependency ws to version 8.18.3, and the provided advisories indicate this version is affected by memory disclosure and memory-exhaustion denial-of-service issues. Because this skill uses viem, which depends on ws for websocket connectivity, a vulnerable websocket client/server library in a DeFi automation context can expose sensitive runtime data or allow service disruption when interacting with untrusted or compromised websocket endpoints.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The documentation describes capabilities beyond the stated skill scope, including reward claiming, token swapping, and auto-compounding. In a real-funds DeFi context, this scope drift is dangerous because users or orchestrating agents may invoke higher-risk operations than expected, increasing the chance of unauthorized asset movement, unintended swaps, or policy bypass.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares capabilities that can access environment data, execute shell commands, and reach the network, yet it provides no explicit permission or allowed-tools boundary. In a skill that handles wallet configuration, private keys, and live DeFi transactions, missing scope declarations materially increases the chance of over-privileged execution and unintended fund-moving behavior.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest description omits reward-claiming and token-swapping even though the documentation presents them as core supported commands. This under-describes what the skill can do with user assets and reduces the ability of reviewers or automated policy systems to make informed trust decisions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using `npx tsx` without pinning a version allows dependency resolution to drift over time or pull an unexpected package version at execution time. In a financial skill that can configure wallets and send blockchain transactions, that creates a supply-chain risk where compromised or changed tooling could affect secret handling or transaction construction.

Intent-Code Divergence

Medium
Confidence
87% confidence
Finding
The security section states keys are never written to disk, yet the setup flow says users can configure a private key file. Contradictory security claims create unsafe operator assumptions about how secrets are stored and handled, which is especially dangerous in a skill that manages real funds.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/config.ts:305

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/config.ts:197