Back to skill

Security audit

StonebornBot

Security checks for vulnerabilities and agentic risk

Overview

This NFT mint bot can perform real irreversible blockchain actions with many wallets, and one test script is documented as safe while actually broadcasting transactions.

Install only if you are comfortable reviewing and controlling a bot that can spend ETH and mint from every configured wallet. Use fresh low-balance wallets, keep private keys out of shared or version-controlled directories, avoid batch-test.js on mainnet unless you intend to broadcast transactions, and verify every contract, calldata, chain ID, gas cap, RPC endpoint, Bankr setting, and Archetype auth source before running.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/batch-test.js:43
Finding
Batch Test Signs and Broadcasts Real Blockchain Transactions Contrary to Documentation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/batch-test.js:43-80`; contradictory documentation at `SKILL.md:69-71` **Vulnerability Type**: Unsafe transaction broadcasting and misleading safety documentation **Risk Level**: High ### Vulnerable Code The Skill documentation states: ```markdown ## Batch Testing Use `scripts/batch-test.js` to test wallet signing speed and RPC connectivity without sending real transactions. ``` However, the test signs and broadcasts transactions: ```javascript // Pre-sign all const signStart = process.hrtime.bigint(); const signed = await Promise.all(signers.map((s, i) => { const tx = { to: cfg.contract.address, data: calldata, value: 0n, chainId: cfg.chainId, type: 2, maxFeePerGas: ethers.parseUnits(cfg.gas.maxFeePerGas, "gwei"), maxPriorityFeePerGas: ethers.parseUnits(cfg.gas.maxPriorityFeePerGas, "gwei"), gasLimit: cfg.gas.gasLimit, nonce: nonces[i], }; return s.signTransaction(tx); })); const signMs = Number(process.hrtime.bigint() - signStart) / 1e6; log("⚡ All " + signed.length + " txs signed in " + signMs.toFixed(0) + "ms"); // Batched broadcast const fireStart = process.hrtime.bigint(); log("🔥 FIRING in batches of " + BATCH_SIZE + "..."); let success = 0, fail = 0; const rpcUrls = cfg.rpcUrls || [cfg.rpcUrl]; for (let b = 0; b < signed.length; b += BATCH_SIZE) { const batchNum = Math.floor(b / BATCH_SIZE) + 1; const totalBatches = Math.ceil(signed.length / BATCH_SIZE); const batch = signed.slice(b, b + BATCH_SIZE); const labels = cfg.wallets.slice(b, b + BATCH_SIZE).map(w => w.label); const results = await Promise.allSettled(batch.map((raw, i) => { // Send to first RPC only to avoid rate limits return fetch(rpcUrls[0], { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_sendRawTransaction", params: [raw] }), }).then(r => r.json()).then(j => { ...[truncated 2292 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all `eth_sendRawTransaction` calls from the default test path. 2. Test RPC connectivity with read-only methods such as `eth_chainId` and `eth_blockNumber`. 3. Test transaction execution with `eth_call` or `eth_estimateGas`, clearly documenting that these methods do not broadcast. 4. Perform signing benchmarks using offline dummy transactions on a designated test chain. 5. If broadcasting is retained as an optional feature: - Require an explicit `--broadcast` command-line flag. - Display the chain ID, target contract, function selector, wallet count, maximum gas cost, and RPC host. - Require explicit interactive confirmation. - Refuse mainnet by default unless a second override flag is supplied. - Provide a dry-run mode that is enabled by default. 6. Rename the script if it remains capable of real broadcasting and correct `SKILL.md` so the behavior is not represented as non-transactional. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mint-bot.js:49
Finding
Wallet Private Keys Are Stored in Plaintext Project-Local Configuration Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mint-bot.js:49-52,496`; `scripts/batch-test.js:13,29`; `references/wallet-management.md:5-22`; `scripts/setup.sh:15-16` **Vulnerability Type**: Plaintext sensitive-data storage **Risk Level**: Medium ### Vulnerable Code The main bot reads a fixed configuration file from the project’s `scripts` directory: ```javascript function loadConfig() { const configPath = path.join(__dirname, "config.json"); if (!fs.existsSync(configPath)) throw new Error("config.json not found."); const cfg = JSON.parse(fs.readFileSync(configPath, "utf-8")); ``` It directly constructs signers from plaintext private keys: ```javascript const signers = cfg.wallets.map((w) => new ethers.Wallet(w.privateKey, provider)); ``` The batch test follows the same pattern: ```javascript const cfg = JSON.parse(fs.readFileSync(path.join(__dirname, "config-test-all.json"), "utf-8")); ``` ```javascript const signers = cfg.wallets.map(w => new ethers.Wallet(w.privateKey, provider)); ``` The documented configuration format explicitly places private keys in JSON: ```json "wallets": [ { "privateKey": "0x...", "label": "wallet-1" }, { "privateKey": "0x...", "label": "wallet-2" } ] ``` The setup script creates the project-local configuration without restricting its permissions: ```bash if [ ! -f config.json ]; then cp ../assets/config-template.json config.json echo "📄 Created config.json from template — edit it with your settings" else echo "⚠️ config.json already exists, skipping" fi ``` ### Technical Analysis Ethereum private keys are bearer credentials that provide irreversible transaction authority. The Skill instructs users to place these credentials unencrypted in JSON and then reads them from fixed files within the project directory. This design conflicts with the wallet guide’s recommendation to store wallet files outside the project directory because the executables do not expose a documented external confi ...[truncated 1655 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Support an explicit external configuration path rather than requiring secrets inside the project directory. 2. Replace raw private-key JSON entries with one or more of: - Encrypted JSON keystores with runtime password entry. - Hardware-wallet or external signer integration. - Operating-system credential storage. - A dedicated secret manager. - Managed remote wallets with tightly scoped credentials. 3. Separate non-sensitive transaction configuration from signing credentials. 4. Create generated secret files with owner-only permissions, such as mode `0600`, and reject files readable by group or other users. 5. Add `config.json`, `config-test-all.json`, keystore files, and similar generated secrets to `.gitignore`. 6. Add startup checks that warn or fail when private-key files are inside a source-controlled directory. 7. Avoid printing generated private keys to standard output in wallet-generation examples. 8. Continue recommending isolated, low-balance minting wallets, but do not treat wallet isolation as a substitute for secure key storage. ]]>

T08 · Insecure Dependencies

Note
Location
scripts/setup.sh:12
Finding
Setup Installs a Range-Unpinned Dependency Without a Committed Lockfile<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:12` **Vulnerability Type**: Non-reproducible third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```bash npm install ethers@^6 ``` ### Technical Analysis The caret version range permits npm to select different compatible `ethers` 6.x releases over time. The setup script creates `package.json` dynamically if it is absent, and the audited project structure does not contain a committed `package-lock.json` that fixes the resolved package graph and integrity hashes. The package is also obtained from the registry configured in the user’s ambient npm settings. Consequently, installation is not reproducible from the audited files alone. A future compromised release, compromised transitive dependency, or unintended registry configuration could introduce code that was not part of this audit. No evidence was found that the current dependency name is typosquatted or that `ethers` itself is malicious. The risk arises from mutable dependency resolution and reliance on an uncontrolled package source. ### Attack Path 1. An attacker compromises a future version accepted by `ethers@^6`, one of its resolved dependencies, or a registry used by the victim. 2. A user follows the documented quick-start procedure and runs `scripts/setup.sh`. 3. npm resolves and downloads the package graph available at installation time rather than an audit-pinned graph. 4. Malicious package installation behavior may run during installation, or malicious library code may execute when the bot imports `ethers`. 5. That code runs with the privileges of the user executing setup or the bot and may access project files, including wallet configuration. ### Impact Assessment If the dependency supply chain is compromised, injected code could run with the invoking user’s local privileges. Depending on that user’s environment, the accessible scope could include: - Project files and plaintext wallet configur ...[truncated 327 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a reviewed `package.json` to the project instead of generating it at installation time. 2. Pin `ethers` to an audited exact version rather than using a caret range. 3. Generate, review, and commit `package-lock.json`. 4. Replace `npm install` in setup with `npm ci` so installation follows the locked dependency graph. 5. Document and enforce the expected HTTPS npm registry. 6. Periodically audit the lockfile with dependency-scanning tools and review updates before merging them. 7. Apply dependency updates through a controlled process that validates package integrity, provenance, and release changes. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (10)

Missing User Warnings

High
Confidence
96% confidence
Finding
The run instructions tell the user to execute the bot in instant or monitor mode without clearly warning that doing so can broadcast real, irreversible blockchain transactions that spend ETH and may trigger unintended mint purchases. Because the skill is explicitly optimized for speed, pre-signing, and multi-RPC broadcast, accidental execution or misconfiguration could rapidly commit funds across many wallets before the user realizes it.

Ae1

High
Category
analysis-evasion
Content
node scripts/mint-bot.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/mint-bot.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill instructs users to configure an array of wallet private keys for 100+ wallets but does not prominently warn that these are highly sensitive secrets whose exposure enables immediate theft of funds and assets. In this context, the omission is especially dangerous because the skill centralizes many private keys in one configuration, creating a high-value target and increasing blast radius if mishandled.

Ae1

High
Category
analysis-evasion
Content
Use `scripts/batch-test.js` to test wallet signing speed and RPC connectivity without sending real transactions.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises network-capable behavior such as RPC, WebSocket, mempool watching, and multi-endpoint broadcasting, but it declares no explicit tool scope or permission boundary. That mismatch increases the chance an agent or user invokes a network-active skill without clear authorization constraints, which is risky given the skill is designed to transmit blockchain transactions.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The guidance explicitly tells users to obtain Archetype auth/invite data by inspecting other users' successful mint transactions and decoding the auth parameter. In the context of a high-speed NFT mint bot designed for sniping and multi-wallet automation, this facilitates reuse or abuse of access credentials intended for allowlisted participants, enabling unauthorized minting, queue-jumping, or bypass of project gating.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script automatically broadcasts pre-signed raw transactions to an RPC endpoint without any interactive confirmation, dry-run mode, or prominent final warning before funds-affecting actions occur. In this skill’s context—a high-speed multi-wallet NFT mint bot handling many private keys and transactions—this increases the risk of accidental mass submission, unwanted spending, and irreversible on-chain actions if the config, target contract, or gas settings are wrong or maliciously altered.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The Bankr helpers transmit bearer credentials and transaction/signing data to an external service, but the file provides no explicit disclosure, consent flow, or trust-boundary warning to the user. This is dangerous because it externalizes signing/submission operations and exposes sensitive operational metadata to a third party, which is especially risky in an automated bot handling multiple wallets and valuable on-chain transactions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script loads raw private keys, pre-signs transactions, and automatically broadcasts them across multiple RPC endpoints or Flashbots without any explicit runtime confirmation, approval gate, or transaction summary acknowledgement. In the context of a high-speed multi-wallet NFT mint bot, this creates a serious risk of unintended asset spend, mass transaction submission, and irreversible loss if configuration is wrong, the target contract is malicious, or the skill is triggered unexpectedly.

Static analysis

No suspicious patterns detected.