Back to skill

Security audit

Kelp Forest

Security checks for vulnerabilities and agentic risk

Overview

This skill is a DeFi staking guide that is mostly coherent, but it asks users to handle live wallet keys and grant broad on-chain asset permissions without enough safety controls.

Review carefully before installing or following this skill. Use only a dedicated low-value wallet, independently verify every contract address and chain ID, prefer a hardware wallet or keystore instead of raw private keys, approve only the exact amount needed, revoke leftover allowances, and treat LP NFT staking as transferring custody to a contract with real loss risk.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T08 · Insecure Dependencies

Warning
Location
skill.md:128
Finding
Unpinned Third-Party Dependency Creates Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `skill.md:128` **Vulnerability Type**: Unpinned package installation **Risk Level**: Medium ### Vulnerable Code ```bash npm install ethers WALLET_KEY=0xYourPrivateKey node kelp-agent.mjs ``` ### Technical Analysis The installation command does not specify an exact reviewed version of `ethers`, and the project does not provide a lockfile or integrity metadata. Consequently, users may install different package versions depending on when the instructions are executed. Because the installed dependency runs in the same environment as code that accesses `WALLET_KEY` and signs blockchain transactions, a compromised package release, registry account, transitive dependency, or package installation mechanism could access sensitive wallet material or modify transaction behavior. The available project evidence does not establish that the current `ethers` package is malicious; the weakness is the uncontrolled and mutable dependency resolution process. ### Attack Path 1. An attacker compromises a relevant package publication account, dependency, or package registry delivery path. 2. The attacker publishes or serves a malicious version that remains compatible with the unrestricted installation command. 3. A user follows the documented `npm install ethers` instruction. 4. The malicious package or dependency executes installation-time code or is imported by the agent script. 5. The package reads `WALLET_KEY`, alters provider or contract behavior, or changes transaction parameters before signing. 6. The attacker obtains the wallet key or causes the user to authorize attacker-controlled blockchain transactions. ### Impact Assessment Successful exploitation could expose the wallet private key and provide full signing authority over the affected wallet. This could allow theft of native assets and tokens, unauthorized approvals, malicious contract interactions, or transfer of NFTs. The scope is limited to environments t ...[truncated 98 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `ethers` to a reviewed exact version rather than using an unconstrained installation: ```bash npm install --save-exact ethers@<reviewed-version> ``` 2. Include a reviewed `package.json` and lockfile in the project. 3. Direct users to install dependencies with: ```bash npm ci ``` 4. Verify and review the resolved dependency tree before distribution. 5. Use package integrity controls and a trusted registry. 6. Disable package lifecycle scripts where they are unnecessary: ```bash npm ci --ignore-scripts ``` 7. Run wallet-signing software in a restricted environment and prefer an external or hardware signer so that dependencies cannot directly read raw private keys. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
skill.md:89
Finding
Excessive MOLT Token Allowances Violate Least Privilege<![CDATA[ ## Vulnerability Details **File Location**: `skill.md:89-96`, `skill.md:436-441`, and `skill.md:612` **Vulnerability Type**: Excessive ERC-20 approval **Risk Level**: High ### Vulnerable Code Primary staking example: ```javascript const allowance = await molt.allowance(wallet.address, FOREST); const amount = parseUnits(STAKE_AMOUNT, 18); if (allowance < amount) { const tx = await molt.approve(FOREST, parseUnits('999999999', 18)); await tx.wait(); console.log(' Approved'); } ``` Migration example: ```javascript const NEW_FOREST = '0x5Bf07C85B2641cF32f206956BC25d9776143df28'; const molt = new Contract(MOLT, ERC20_ABI, wallet); await molt.approve(NEW_FOREST, parseUnits('999999999', 18)); const newForest = new Contract(NEW_FOREST, FOREST_ABI, wallet); await newForest.registerAgent('my-agent'); await newForest.deposit(0, await molt.balanceOf(wallet.address)); ``` Command-line example: ```bash cast send $MOLT "approve(address,uint256)" $FOREST $(cast max-uint) --rpc-url $RPC --private-key $PK ``` ### Technical Analysis The JavaScript examples approve `999,999,999` MOLT, while the command-line example grants the maximum possible `uint256` allowance. These approvals substantially exceed the amount required for the demonstrated deposit. ERC-20 allowances generally remain active until consumed or explicitly revoked. The authorization therefore persists after the immediate staking transaction and may apply to MOLT acquired by the wallet in the future. The security of the wallet's MOLT balance becomes dependent on the approved spender remaining trustworthy and uncompromised for the entire lifetime of the allowance. The project contains only documentation and client examples, not the source code of the referenced on-chain contracts. The audit therefore cannot verify the spender contracts' implementation, upgrade controls, or resistance to compromise. ### Attack Path 1. The user follows the instructions and grants the staking contract an ext ...[truncated 949 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Approve only the exact amount required for the immediate deposit: ```javascript const amount = parseUnits(STAKE_AMOUNT, 18); await (await molt.approve(FOREST, amount)).wait(); await (await forest.deposit(POOL_ID, amount)).wait(); ``` 2. Revoke any remaining allowance after the operation: ```javascript await (await molt.approve(FOREST, 0)).wait(); ``` 3. For tokens requiring allowance to be reset before changing it, first approve zero and then approve the exact amount. 4. Replace the `cast max-uint` example with a bounded value matching the intended deposit. 5. Display the chain ID, token address, spender address, amount, and existing allowance for explicit user confirmation before signing. 6. Verify deployed contract bytecode, ownership, upgradeability, and official address provenance before requesting approval. 7. Prefer short-lived permit-based authorization or transaction batching when supported. 8. Add instructions for periodically reviewing and revoking stale allowances. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
skill.md:609
Finding
Raw Wallet Private Key Is Passed Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `skill.md:609-647` **Vulnerability Type**: Insecure secret handling **Risk Level**: High ### Vulnerable Code ```bash cast send $FOREST "registerAgent(string)" "my-agent" --rpc-url $RPC --private-key $PK cast send $MOLT "approve(address,uint256)" $FOREST $(cast max-uint) --rpc-url $RPC --private-key $PK cast send $FOREST "deposit(uint256,uint256)" 0 $(cast --to-wei 1000) --rpc-url $RPC --private-key $PK cast send $FOREST "harvestAll()" --rpc-url $RPC --private-key $PK cast send $FOREST_V4 "registerAgent(string)" "v4-agent" --rpc-url $RPC --private-key $PK cast send $POS_MGR "safeTransferFrom(address,address,uint256)" $MY_ADDR $FOREST_V4 <TOKEN_ID> --rpc-url $RPC --private-key $PK cast send $FOREST_V4 "harvest(uint256)" <TOKEN_ID> --rpc-url $RPC --private-key $PK cast send $FOREST_V4 "harvestAll()" --rpc-url $RPC --private-key $PK cast send $FOREST_V4 "unstake(uint256)" <TOKEN_ID> --rpc-url $RPC --private-key $PK cast send $FOREST_V4 "autoHarvest(address[])" "[0xUSER1,0xUSER2]" --rpc-url $RPC --private-key $PK ``` ### Technical Analysis The documented commands expand `$PK` and pass the raw private key to `cast` through the `--private-key` command-line argument. While a normal interactive shell generally records the literal command rather than the expanded value in history, the expanded secret may be exposed through process argument inspection, shell tracing, CI/CD diagnostics, terminal recording, error reporting, endpoint monitoring, or command-execution wrappers. Any process or user able to inspect the arguments during execution may recover the private key. This risk is especially significant because the same wallet is used to approve tokens, transfer LP NFTs, and sign contract calls. ### Attack Path 1. The user exports the wallet private key into `$PK`. 2. The user runs one of the documented `cast send` commands. 3. The shell expands `$PK`, placing the raw private key in the spawned process' ...[truncated 901 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all examples that pass raw private keys through `--private-key`. 2. Use an encrypted Foundry keystore and account-based signing, for example: ```bash cast wallet import kelp-agent --interactive cast send <address> "<function-signature>" <arguments> \ --account kelp-agent \ --rpc-url "$RPC" ``` 3. Prefer a hardware wallet, isolated signing service, or other external signer for wallets holding valuable assets. 4. Ensure signing tools prompt users to review the destination, chain ID, function selector, token amount, and allowance before authorization. 5. Disable shell tracing before any operation that handles secrets and prevent CI systems from printing command arguments. 6. Avoid placing private keys in persistent shell startup files or plaintext configuration files. 7. If a private key has already appeared in process logs, traces, or monitoring systems, treat it as compromised and migrate all assets and permissions to a newly generated wallet. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Missing User Warnings

High
Confidence
99% confidence
Finding
The script requests an effectively unlimited ERC-20 approval via a very large allowance, which exposes the user's MOLT balance to unrestricted spending by the approved contract for as long as the approval remains active. If the contract is compromised, upgraded maliciously, or behaves unexpectedly, a user can lose substantially more than the intended staking amount.

Missing User Warnings

High
Confidence
97% confidence
Finding
The instructions tell users to transfer Uniswap V3 LP NFTs directly into the staking contract, which transfers custody of valuable positions and may apply fees or expose the assets to contract-specific risks. Without an explicit warning, users may not understand that the NFT leaves their wallet, may be difficult to recover if the contract misbehaves, and can represent significant underlying capital.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill directs users to provide a live wallet private key and execute real on-chain transactions, but it does not include clear safety guidance about key custody, use of burner wallets, chain verification, transaction review, or the risk of irreversible loss of funds. In a DeFi staking context, this omission is dangerous because users may paste production keys into ad hoc scripts and expose assets to theft or operational mistakes.

Static analysis

No suspicious patterns detected.