Back to skill

Security audit

Apiosk Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it needs review because it handles a funded crypto wallet while storing keys in plaintext, recommending unsafe installer commands, and documenting a payment flow the shipped clients do not implement.

Review carefully before installing. Use only a disposable wallet with very small funds, do not reuse an existing wallet, avoid sending sensitive data through the API gateway, and do not run the documented `curl | bash` installer without independent verification. Treat the automatic-payment claims as unproven until the client implements real signed x402 authorization and enforceable spending limits.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
setup-wallet.sh:23
Finding

Unpinned Remote Installer Is Piped Directly into a Shell

Content
View full analysis
/dev/null; then echo "" echo "❌ 'cast' not found. Foundry is required to generate wallets." echo "" echo "To install Foundry, run:" echo " curl -L https://foundry.paradigm.xyz | bash" echo " foundryup" echo "" echo "Or visit: https://book.getfoundry.sh/getting-started/installation" ``` `check-balance.sh:21-29`: ```bash # Check USDC balance on-chain if command -v cast &> /dev/null; then BALANCE_WEI=$(cast call "$USDC_CONTRACT" "balanceOf(address)(uint256)" "$WALLET_ADDRESS" --rpc-url "$RPC_URL") BALANCE_USDC=$(echo "scale=2; $BALANCE_WEI / 1000000" | bc) echo "💰 USDC Balance: $BALANCE_USDC USDC" else echo "⚠️ Install Foundry to check on-chain balance: curl -L https://foundry.paradigm.xyz | bash" fi ``` `README.md:55-60`: ```bash 3. **Foundry installation:** This skill requires Foundry (cast command). Install it manually: ```bash curl -L https://foundry.paradigm.xyz | bash foundryup ``` ``` `SECURITY.md:48-53`: ```bash The skill requires Foundry (cast command) for wallet generation. Install manually: ```bash curl -L https://foundry.paradigm.xyz | bash foundryup ``` ``` ### Technical Analysis The recommended command downloads a mutable response from an external URL and immediately executes it with Bash. The downloaded content is not pinned to a release, authenticated with a detached signature, checked against a known digest, or saved for inspection before execution. Although the current URL is presented as the official Foundry installer, the effective code executed by users can change after the Skill has been audited. Compromise of the hosting infrastructure, upstream in ...[truncated 1790 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
setup-wallet.sh:37
Finding

Funded Wallet Private Key Is Stored in Plaintext and Loaded Unnecessarily

Content
View full analysis
"$WALLET_FILE" << EOF { "address": "$ADDRESS", "private_key": "$PRIVATE_KEY", "created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)" } EOF chmod 600 "$WALLET_FILE" ``` `call-api.sh:27-40`: ```bash # Load wallet if [ ! -f "$WALLET_FILE" ]; then echo "❌ Wallet not found. Run ./setup-wallet.sh first" exit 1 fi WALLET_ADDRESS=$(jq -r '.address' "$WALLET_FILE") WALLET_KEY=$(jq -r '.private_key' "$WALLET_FILE") GATEWAY_URL=$(jq -r '.gateway_url' "$CONFIG_FILE") # Make request RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$GATEWAY_URL/$API_ID" \ -H "Content-Type: application/json" \ -H "X-Wallet-Address: $WALLET_ADDRESS" \ -d "$PARAMS") ``` `apiosk-client.js:16-24`: ```javascript function loadWallet() { if (!fs.existsSync(WALLET_FILE)) { throw new Error('Wallet not found. Run ./setup-wallet.sh first'); } const wallet = JSON.parse(fs.readFileSync(WALLET_FILE, 'utf8')); const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); return { wallet, config }; } ``` `apiosk_client.py:15-26`: ```python def load_wallet(): """Load wallet configuration""" if not WALLET_FILE.exists(): raise FileNotFoundError('Wallet not found. Run ./setup-wallet.sh first') with open(WALLET_FILE) as f: wallet = json.load(f) with open(CONFIG_FILE) as f: config = json.load(f) return wallet, config ``` ### Technical Analysis The wallet setup script wr ...[truncated 1840 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
call-api.sh:33
Finding

Claimed x402 Payment Flow Has No Cryptographic Authorization

Content
View full analysis
{ const data = JSON.stringify(params); const options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': data.length, 'X-Wallet-Address': wallet.address, } }; const req = https.request(url, options, (res) => { ``` `apiosk_client.py:44-53`: ```python wallet, config = load_wallet() params = params or {} url = f"{config['gateway_url']}/{api_id}" headers = { 'Content-Type': 'application/json', 'X-Wallet-Address': wallet['address'], } response = requests.post(url, json=params, headers=headers) ``` The documented flow in `SKILL.md:280-288` states: ```text 1. Make request 2. Gateway returns 402 Payment Required 3. Your wallet signs payment proof 4. Gateway verifies on-chain 5. Gateway forwards to API 6. You get response ``` ### Technical Analysis The clients do not implement the documented x402 challenge-response flow. They do not parse payment terms from a 402 response, construct a payment authorization, sign a domain-separated message, submit a transaction, include a signed payment proof, or provide a nonce ...[truncated 2225 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

External Script Fetching

High
Category
Supply Chain
Confidence
98% confidence
Finding

The README instructs users to execute a remote script directly with curl piped to bash, which creates a supply-chain and remote-code-execution risk. If the hosting endpoint, network path, or served installer is compromised, users may run attacker-controlled code on their system with their current user privileges, which is especially dangerous in a skill that manages cryptocurrency wallet material.

Content

Scanner excerpt · README.md (reported line 58)May include surrounding context.

  1. Foundry installation: This skill requires Foundry (cast command). Install it manually:
    bash
    curl -L https://foundry.paradigm.xyz | bash
    foundryup
    

Chaining Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The use of | bash is a direct execution chain from untrusted network content to a shell, bypassing meaningful user review and increasing the chance of silent compromise. In the context of a payment/API skill that stores wallet credentials locally, compromise of the host could lead to theft of funds, credential exfiltration, or persistence on the agent machine.

Content

Scanner excerpt · README.md (reported line 58)May include surrounding context.

  1. Foundry installation: This skill requires Foundry (cast command). Install it manually:
    bash
    curl -L https://foundry.paradigm.xyz | bash
    foundryup
    

External Script Fetching

High
Category
Supply Chain
Confidence
96% confidence
Finding

The documentation recommends installing a dependency via curl ... | bash, which executes remotely fetched code without prior integrity verification. If the remote server, DNS, TLS termination, or distribution path is compromised, users could execute arbitrary attacker-controlled code on their system during setup.

Content

Scanner excerpt · SECURITY.md (reported line 51)May include surrounding context.

The skill requires Foundry (cast command) for wallet generation. Install manually:

bash
curl -L https://foundry.paradigm.xyz | bash
foundryup

Chaining Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The | bash construct is a classic dangerous chaining pattern because it immediately feeds untrusted network content into a shell interpreter. In a skill that manages wallet keys and cryptocurrency-related operations, compromise of the setup environment is especially dangerous because it could lead to credential theft, wallet exfiltration, or malicious transaction tooling.

Content

Scanner excerpt · SECURITY.md (reported line 51)May include surrounding context.

The skill requires Foundry (cast command) for wallet generation. Install manually:

bash
curl -L https://foundry.paradigm.xyz | bash
foundryup

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · check-balance.sh (reported line 28)May include surrounding context.

sh
BALANCE_USDC=$(echo "scale=2; $BALANCE_WEI / 1000000" | bc)
  echo "💰 USDC Balance: $BALANCE_USDC USDC"
else
  echo "⚠️  Install Foundry to check on-chain balance: curl -L https://foundry.paradigm.xyz | bash"
fi

# Check usage via Apiosk gateway

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · setup-wallet.sh (reported line 29)May include surrounding context.

sh
BALANCE_USDC=$(echo "scale=2; $BALANCE_WEI / 1000000" | bc)
  echo "💰 USDC Balance: $BALANCE_USDC USDC"
else
  echo "⚠️  Install Foundry to check on-chain balance: curl -L https://foundry.paradigm.xyz | bash"
fi

# Check usage via Apiosk gateway

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 49)May include surrounding context.

md
### Private Key Storage

The Apiosk skill stores wallet private keys in `~/.apiosk/wallet.json` with restrictive file permissions (chmod 600). **The private key is stored in plaintext.**

**This is suitable for:**
- Testing and development

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SECURITY.md (reported line 7)May include surrounding context.

md
### Private Key Storage

The Apiosk skill stores wallet private keys in `~/.apiosk/wallet.json` with restrictive file permissions (chmod 600). **The private key is stored in plaintext.**

**This is suitable for:**
- Testing and development

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 39)May include surrounding context.

md
### Private Key Storage

The Apiosk skill stores wallet private keys in `~/.apiosk/wallet.json` with restrictive file permissions (chmod 600). **The private key is stored in plaintext.**

**This is suitable for:**
- Testing and development

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · setup-wallet.sh (reported line 51)May include surrounding context.

sh
### Private Key Storage

The Apiosk skill stores wallet private keys in `~/.apiosk/wallet.json` with restrictive file permissions (chmod 600). **The private key is stored in plaintext.**

**This is suitable for:**
- Testing and development

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill encourages immediate API use and automatic micropayments but does not prominently warn that request parameters are sent to external services and may trigger real spending. In an agent setting, this can lead to unreviewed transmission of sensitive user data and unintended financial loss, especially when calls are automated or repeated in loops. The danger is elevated by the 'no setup' and 'just pay and call' framing, which downplays consent and budgeting concerns.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This script transmits caller-supplied parameters and a wallet identifier to an external network service. In context, external transmission is the intended feature, but it still creates security risk because agents may forward sensitive prompts, personal data, internal URLs, or other untrusted content to a third-party gateway while also triggering paid actions. The risk is increased by the generic API interface and support for APIs like code execution, web screenshots, and file conversion.

Content

Scanner excerpt · SKILL.md (reported line 160)May include surrounding context.

md
# Make request (x402 payment happens via on-chain verification)
# The gateway validates payment on-chain, no client-side signature needed
curl -X POST "https://gateway.apiosk.com/$API_ID" \
  -H "Content-Type: application/json" \
  -H "X-Wallet-Address: $WALLET_ADDRESS" \
  -d "$PARAMS"

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation describes a payment flow where the wallet signs payment proof, but the provided client example only sends an unauthenticated wallet address header. If the gateway really accepts requests based only on a claimed address, anyone could impersonate another wallet, misattribute charges, or bypass payment/authentication controls. Even if the backend is secure, this mismatch is dangerous because it encourages insecure integrations and gives users a false sense of how authorization works.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 392)May include surrounding context.

bash
# 1. Sign up
curl -X POST https://dashboard.apiosk.com/api/register \
  -d '{"email":"you@example.com","api_name":"My API"}'

# 2. Add your API endpoint

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The top-level documentation says the client provides 'Easy API calls with automatic x402 payment'. However, the implementation just sends requests with an X-Wallet-Address header and explicitly treats a 402 response as a failure by raising ValueError. That is an active contradiction between the documented behavior and the code's actual handling of payment.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · apiosk_client.py (reported line 53)May include surrounding context.

python
'X-Wallet-Address': wallet['address'],
    }
    
    response = requests.post(url, json=params, headers=headers)
    
    if response.status_code == 200:
        return response.json()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code sends user-supplied parameters and the wallet address to a remote gateway via HTTP POST, but the function provides no confirmation prompt, logging, or warning beyond a generic docstring. For a reusable client library, this means potentially sensitive request data is transmitted without visible disclosure at the point of use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The balance and usage helper functions make HTTP GET requests containing the wallet address as a query parameter, but there is no explicit warning, prompt, or user-facing disclosure in these functions. Although network access is part of the client purpose, the transmission of wallet-linked data is not clearly disclosed in the function-level documentation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script extracts .private_key from the wallet file, which is a sensitive credential access operation. Although the file has brief usage comments, there is no confirmation, warning, or user-facing disclosure that the script will read wallet credentials from disk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
77% confidence
Finding

The script performs a POST request to a gateway URL loaded from local configuration without validating the destination, protocol, or trust boundary. If the config is altered or maliciously provisioned, user-supplied data and the wallet address can be sent to an attacker-controlled endpoint, enabling data leakage and transaction-metadata exposure.

Content

Scanner excerpt · call-api.sh (reported line 38)May include surrounding context.

sh
GATEWAY_URL=$(jq -r '.gateway_url' "$CONFIG_FILE")

# Make request
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$GATEWAY_URL/$API_ID" \
  -H "Content-Type: application/json" \
  -H "X-Wallet-Address: $WALLET_ADDRESS" \
  -d "$PARAMS")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script performs an HTTP POST to $GATEWAY_URL/$API_ID and transmits the user-provided JSON parameters in the request body. While making an API call is part of the script's purpose, the file does not include a clear disclosure that supplied parameters and wallet address are sent to a remote service.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.