Back to skill

Security audit

Exoskeletons

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for an onchain NFT identity tool, but its examples encourage submitting real blockchain transactions through a third-party API with an API key and unsafe shell execution.

Review before installing. Only use this skill if you are comfortable with an agent building and potentially submitting Base transactions. Prefer wallet-native signing or a structured HTTPS client over the documented shell `curl`/`execSync` examples, use a restricted Bankr key, and confirm transaction destination, chain ID, value, and calldata before broadcasting.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:650
Finding
Shell Command Injection and API Key Exposure in Transaction Submission Example<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 650-656 **Vulnerability Type**: Shell command injection and insecure credential handling **Risk Level**: Medium ### Vulnerable Code ```javascript function submitTx(tx) { const result = JSON.parse(execSync( `curl -s -X POST https://api.bankr.bot/agent/submit ` + `-H "X-API-Key: ${process.env.BANKR_API_KEY}" ` + `-H "Content-Type: application/json" ` + `-d '${JSON.stringify({ transaction: tx })}'` ).toString()); console.log(`TX: ${result.transactionHash}`); return result; } ``` The example imports the shell execution function at `SKILL.md:625`: ```javascript import { execSync } from "child_process"; ``` ### Technical Analysis The documented transaction workflow constructs a shell command by directly interpolating `process.env.BANKR_API_KEY` and serialized transaction data into a string passed to `execSync`. By default, string-based `execSync` executes the command through a system shell. Shell quoting does not provide a reliable security boundary here: - The API key is placed inside double quotes, where shell substitutions and some metacharacters may still be interpreted. - The serialized transaction is placed inside single quotes. An apostrophe in attacker-influenced data could terminate that quoted argument and introduce additional shell commands. - The expanded API key becomes part of the spawned process command line and may be exposed through local process inspection, diagnostic output, crash reporting, or command logging. - The code does not validate the transaction destination, chain ID, transferred value, or calldata immediately before submission. The helper library normally emits constrained hexadecimal transaction fields, which reduces exposure when only its standard builders are used. However, `submitTx` accepts an arbitrary object, and the example establishes an unsafe pattern that users may reuse with externally supplied transaction data. ### Atta ...[truncated 1186 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace shell-based `curl` execution with Node.js `fetch` so neither the credential nor request body is interpreted by a shell: ```javascript async function submitTx(tx) { validateTransaction(tx); const response = await fetch("https://api.bankr.bot/agent/submit", { method: "POST", headers: { "X-API-Key": process.env.BANKR_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ transaction: tx }), }); if (!response.ok) { throw new Error(`Bankr request failed with status ${response.status}`); } const result = await response.json(); console.log(`TX: ${result.transactionHash}`); return result; } ``` Apply the following additional controls: 1. Confirm that `BANKR_API_KEY` is present without printing or logging it. 2. Validate `tx.to` against an explicit allowlist of expected contracts. 3. Require `tx.chainId === 8453`. 4. Parse and enforce an upper limit on `tx.value`. 5. Verify that `tx.data` is hexadecimal and that its function selector matches the intended operation. 6. Present the destination, operation, and value for explicit user approval before submission. 7. Use a restricted Bankr credential with the minimum available permissions. 8. If an external process is unavoidable, use `execFileSync` or `spawn` with a fixed executable and argument array, with `shell: false`; do not place secrets directly in a shell command string. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:49
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 49 and 57 **Vulnerability Type**: Unpinned package dependency and non-reproducible installation **Risk Level**: Low ### Vulnerable Code The prerequisite specifies an unversioned dependency: ```markdown - **`ethers`** package (`npm install ethers`) ``` The quick-start installation command is also unpinned: ```bash npm install ethers ``` ### Technical Analysis The Skill instructs users to install `ethers` from the configured npm registry without specifying an exact reviewed version, committed lockfile, or integrity-protected dependency tree. The package name is not indicative of typosquatting and no malicious dependency was identified during this audit. Nevertheless, the installation process resolves whatever release and transitive dependency versions are current at execution time. This creates a non-reproducible supply-chain boundary: future package compromise, malicious maintainer activity, registry compromise, or an incompatible release could change the code installed after the Skill has already been reviewed. Depending on npm configuration and package metadata, dependency lifecycle scripts may execute during installation with the user's operating-system privileges. ### Attack Path 1. A user follows the Skill's quick-start instructions at a later date. 2. The npm registry, package publisher account, package release, or a transitive dependency is compromised. 3. `npm install ethers` resolves the compromised or otherwise unreviewed release. 4. Malicious code executes through an installation lifecycle script or when `exoskeleton.js` imports and uses the package. 5. The malicious package gains the permissions of the Node.js process and access to data available in that environment. ### Impact Assessment A compromised dependency could execute arbitrary JavaScript with the user's privileges. Potential scope includes user-accessible files, environment variables, network access, and a ...[truncated 262 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a `package.json` that pins an audited exact version of `ethers` rather than using a floating range. 2. Generate and commit `package-lock.json` so the complete transitive dependency tree and integrity hashes are fixed. 3. Replace `npm install ethers` in the documentation with `npm ci`. 4. Review dependency changes before updating the lockfile. 5. Use automated dependency vulnerability and provenance checks. 6. Where compatible with the package, consider installation with lifecycle scripts disabled: ```bash npm ci --ignore-scripts ``` 7. Document the tested Node.js and `ethers` versions to make installations reproducible. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (14)

Exfiltration Commands

High
Category
Prompt Injection
Content
- **Visual identity** — procedural animated SVG art that encodes who you are (reputation as complexity, activity as density, capabilities as color)
- **Name & bio** — onchain identity you choose
- **Communication** — send messages to any other Exoskeleton (direct, broadcast, or channels)
- **Storage** — per-token key-value store + Net Protocol cloud storage
- **Reputation** — provable track record (age, messages, storage writes, modules, external scores from games/protocols)
- **Modules** — upgradeable capabilities via the Module Marketplace (free + premium)
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Ae1

High
Category
analysis-evasion
Content
- **The `exoskeleton.js` helper library** (included in this project)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **The `exoskeleton.js` helper library** (included in this project)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **The `exoskeleton.js` helper library** (included in this project)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **The `exoskeleton.js` helper library** (included in this project)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **The `exoskeleton.js` helper library** (included in this project)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

External Transmission

Medium
Category
Data Exfiltration
Content
Submit the transaction via Bankr:
```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction": TX_JSON}'
Confidence
94% confidence
Finding
The skill instructs the agent to submit transaction JSON to an external service (Bankr) and to send an API key in the request header. Even if this is framed as normal functionality, it creates a data egress path for transaction contents and secrets, and could enable unintended signing or submission through a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
Submit the transaction via Bankr:
```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction": TX_JSON}'
Confidence
94% confidence
Finding
The skill instructs the agent to submit transaction JSON to an external service (Bankr) and to send an API key in the request header. Even if this is framed as normal functionality, it creates a data egress path for transaction contents and secrets, and could enable unintended signing or submission through a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
**Submit using Bankr's direct API** (recommended):

```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction": TX_JSON}'
Confidence
94% confidence
Finding
This repeats the recommendation to use Bankr's direct API for transaction submission, again establishing an outbound network path and dependency on an external service. Because the agent may be operating with privileged transaction context, sending requests off-platform can expose sensitive metadata or trigger real financial actions.

External Transmission

Medium
Category
Data Exfiltration
Content
**Submit using Bankr's direct API** (recommended):

```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction": TX_JSON}'
Confidence
94% confidence
Finding
This repeats the recommendation to use Bankr's direct API for transaction submission, again establishing an outbound network path and dependency on an external service. Because the agent may be operating with privileged transaction context, sending requests off-platform can expose sensitive metadata or trigger real financial actions.

Session Persistence

Medium
Category
Rogue Agent
Content
**Storage:**
- `setData(uint256 tokenId, bytes32 key, bytes value)` — Store key-value data
- `getData(uint256 tokenId, bytes32 key) → bytes` — Read stored data
- `setNetProtocolOperator(uint256 tokenId, address operator)` — Set cloud storage pointer

**Reputation:**
Confidence
55% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

External Transmission

Medium
Category
Data Exfiltration
Content
function submitTx(tx) {
  const result = JSON.parse(execSync(
    `curl -s -X POST https://api.bankr.bot/agent/submit ` +
    `-H "X-API-Key: ${process.env.BANKR_API_KEY}" ` +
    `-H "Content-Type: application/json" ` +
    `-d '${JSON.stringify({ transaction: tx })}'`
Confidence
98% confidence
Finding
The example uses execSync to construct and execute a curl command that includes the API key and serialized transaction data inline. This is more dangerous than a static curl snippet because it encourages shell execution with secrets in command strings, increasing the risk of credential leakage, command injection bugs, process-list exposure, and accidental submission of transactions.

External Transmission

Medium
Category
Data Exfiltration
Content
function submitTx(tx) {
  const result = JSON.parse(execSync(
    `curl -s -X POST https://api.bankr.bot/agent/submit ` +
    `-H "X-API-Key: ${process.env.BANKR_API_KEY}" ` +
    `-H "Content-Type: application/json" ` +
    `-d '${JSON.stringify({ transaction: tx })}'`
Confidence
98% confidence
Finding
The example uses execSync to construct and execute a curl command that includes the API key and serialized transaction data inline. This is more dangerous than a static curl snippet because it encourages shell execution with secrets in command strings, increasing the risk of credential leakage, command injection bugs, process-list exposure, and accidental submission of transactions.

External Transmission

Medium
Category
Data Exfiltration
Content
*   // Writing (returns transaction JSON for Bankr)
 *   const tx = exo.buildSetName(1, "Atlas");
 *   const tx = exo.buildSendMessage(1, 42, ethers.ZeroHash, 0, "hello!");
 *   // Submit `tx` via Bankr: curl -X POST https://api.bankr.bot/agent/submit ...
 *
 * CLI:
 *   node exoskeleton.js 1
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.