Back to skill

Security audit

Scout Commerce

Security checks for vulnerabilities and agentic risk

Overview

This skill matches its shopping and crypto-swap purpose, but it can spend wallet funds and stores transaction credentials with shipping details in a local plaintext file without strong safeguards.

Install only if you are comfortable with an agent-accessible tool that can place orders and execute swaps from a funded Crossmint wallet. Keep credentials.json private, prefer an isolated environment, fund only limited amounts, review purchase and swap commands before they run, and consider rotating or revoking the API key if the file may have been exposed.

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
scripts/config.py:50
Finding
Transaction-Authorizing API Key and Shipping PII Stored Without Explicit Access Restrictions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:50-59`; sensitive credential construction occurs at `scripts/get_api_key.py:94-105` **Vulnerability Type**: Plaintext sensitive-data storage with insufficient file-permission enforcement **Risk Level**: Medium ### Vulnerable Code ```python def save_credentials(creds: dict) -> bool: """Save credentials to credentials.json file.""" try: with open(CREDS_FILE, "w") as f: json.dump(creds, f, indent=2) return True except IOError as e: print(f"❌ Failed to save credentials: {e}", file=sys.stderr) return False ``` The data written through this function includes: ```python creds = { "api_key": result["apiKey"], "wallet_address": result["walletAddress"], "shipping_profile": { "email": args.email, "address": args.address, **({"phone": args.phone} if args.phone else {}), }, } save_credentials(creds) ``` ### Technical Analysis The Skill stores a transaction-authorizing Scout API key alongside the user's wallet address, email, physical shipping address, and optional phone number in plaintext. The file is opened using the process's default creation mode, so its effective permissions depend on the ambient `umask`. The implementation does not explicitly enforce owner-only access, check whether the destination is a symbolic link, or use atomic file replacement. The `.gitignore` entry for `credentials.json` reduces the chance of accidental Git commits, but it does not protect the file from other local users, compromised processes, overly broad backups, or filesystem synchronization tools. This is particularly sensitive because `SKILL.md` states that the API key authorizes transactions from the custodial wallet. A permissive `umask` can result in credentials readable by unintended local principals. Rewriting an existing file also preserves potentially unsafe permissions. If an attacker can pre-create or rep ...[truncated 1553 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the credential file with explicit owner-only permissions: - Use `os.open()` with `os.O_WRONLY | os.O_CREAT | os.O_TRUNC` and mode `0o600`. - Apply `os.chmod(CREDS_FILE, 0o600)` when migrating or rewriting an existing file. 2. Write credentials atomically: - Create a temporary file in the same directory with mode `0600`. - Flush and `fsync()` it. - Replace the destination using `os.replace()`. 3. Reject unsafe filesystem targets: - Use `O_NOFOLLOW` where supported. - Verify that the destination is not a symbolic link. - Ensure the parent directory is trusted and not writable by unrelated users. 4. Prefer an operating-system keyring or dedicated secret manager for the API key rather than storing it in a JSON file. 5. Minimize retained PII. Store shipping information only when the user explicitly opts in, and provide a command to delete saved credentials and shipping data. 6. Separate the API key from the shipping profile so compromise of one storage mechanism does not automatically disclose both authorization data and personal information. 7. Implement API-side safeguards such as key rotation, revocation, transaction limits, destination restrictions, and user confirmation for value-moving operations. 8. Avoid returning the credential value in command output or logs, and document the local file's sensitivity and required permissions. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:3
Finding
Unpinned and Unused Financial Dependencies Expand the Supply-Chain Attack Surface<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:3-10` **Vulnerability Type**: Unbounded dependency resolution and unnecessary privileged dependency installation **Risk Level**: Medium ### Vulnerable Code ```text # x402 Protocol - handles payment signing/submission x402[httpx,svm]>=2.0.0 # Solana - for wallet operations solana>=0.34.0 solders>=0.21.0 # Utilities base58>=2.1.0 ``` ### Technical Analysis Every dependency uses a lower-bound-only version constraint. Consequently, a future installation may resolve to package versions and transitive dependencies that were not present or reviewed when the Skill was published. The requirements file also lacks integrity hashes and a lock file, preventing installers from verifying an exact reviewed dependency set. The reviewed Python scripts do not import `x402`, `solana`, `solders`, or `base58`. Installing these packages is therefore unnecessary for the observed implementation. In particular, `x402[httpx,svm]` introduces a payment-signing-oriented dependency tree and optional extras despite the scripts implementing network requests through `requests` or the Python standard library. Python packages and their build backends can execute code during installation. An upstream compromise, malicious future release, compromised transitive package, or unsafe package-index configuration could therefore introduce code execution before the Skill is used. This risk is amplified because the runtime environment may contain a funded-wallet API key and shipping PII. The audit did not establish that any currently published dependency version is malicious. The vulnerability is the uncontrolled and unnecessary supply-chain exposure created by the dependency specification. ### Attack Path 1. A user follows the installation instruction and runs `pip install -r scripts/requirements.txt`. 2. The resolver selects the newest versions satisfying the broad `>=` constraints, including their transitive depen ...[truncated 1350 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `x402`, `solana`, `solders`, and `base58` unless the implementation genuinely imports and requires them. 2. Declare the actual direct dependency used by the reviewed request-based scripts, such as a vetted exact version of `requests`. 3. Pin every direct and transitive dependency to an exact reviewed version using a generated lock file. 4. Require package hashes, for example through a hash-locked requirements file installed with `pip --require-hashes`. 5. Generate locks through a reproducible dependency-management workflow and review dependency changes before updates. 6. Use the official Python Package Index over HTTPS and prevent unintended fallback to untrusted or private indexes. 7. Install the Skill in an isolated virtual environment under a non-privileged account. 8. Add automated dependency vulnerability, provenance, and license scanning to the release process. 9. Avoid installing wallet-signing or payment packages in the same environment as transaction-authorizing credentials unless their functionality is strictly necessary. 10. Test the minimal locked dependency set in a clean environment to ensure removal of unused packages does not affect declared functionality. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (53)

Credential Access

High
Category
Privilege Escalation
Content
# Credentials - DO NOT COMMIT
credentials.json

# Python
__pycache__/
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Undeclared wallet token enumeration and related blockchain/RPC access expand the sensitivity of the skill beyond simple shopping/search. In a wallet-linked environment, even read-only balance and token-inspection actions expose financial metadata and should be clearly disclosed as part of the skill's behavior.

Credential Access

High
Category
Privilege Escalation
Content
**List wallet tokens** → `python swap.py --list`

All commands run from `scripts/` folder. API key loads automatically from `credentials.json`.

## Setup (one-time)
Confidence
94% confidence
Finding
Automatic loading of an API key from `credentials.json` indicates the skill accesses locally stored credentials to authorize account and wallet-linked operations. Credential access is inherently sensitive here because the same file may enable order queries, purchases, and exposure of associated personal data if read by unauthorized code or tools.

Credential Access

High
Category
Privilege Escalation
Content
python get_api_key.py --email <EMAIL> --address "<NAME>,<STREET>,<CITY>,<STATE>,<ZIP>,<COUNTRY>"
```

Creates a **Crossmint wallet** + **API key** and stores them in `credentials.json`. Fund the wallet with USDC to buy.

**Keep API key secure** - it authorizes transactions from your wallet.
Confidence
97% confidence
Finding
The skill explicitly instructs users to store a wallet-authorizing API key in `credentials.json`, alongside a wallet address and shipping profile. Because the API key authorizes wallet transactions, compromise of this local file could directly enable unauthorized purchases or account misuse, making this especially dangerous for a shopping skill tied to funds and PII.

Credential Access

High
Category
Privilege Escalation
Content
| `OUT_OF_STOCK` | Search for alternatives |
| `OVER_LIMIT` | Max $1,500 per order |

## Credentials (`credentials.json`)

```json
{
Confidence
96% confidence
Finding
The dedicated credentials section normalizes the presence of a plaintext file containing an API key, wallet address, and shipping profile. Centralizing these high-value fields in an easily discoverable local file raises the likelihood of accidental disclosure through logs, backups, repository mistakes, or other tools with file-read access.

Missing User Warnings

High
Confidence
96% confidence
Finding
The script performs a purchase immediately after parsing CLI arguments, with no interactive confirmation, dry-run preview, or explicit acknowledgment that funds will be charged from the linked wallet. In a commerce skill that can spend real USDC, this increases the risk of accidental or unintended purchases from mistyped locators, manipulated upstream agent behavior, or silent automation.

Credential Access

High
Category
Privilege Escalation
Content
def save_credentials(creds: dict) -> bool:
    """Save credentials to credentials.json file."""
    try:
        with open(CREDS_FILE, "w") as f:
            json.dump(creds, f, indent=2)
Confidence
91% confidence
Finding
This function writes credentials to credentials.json in plaintext. Persisting secrets and personal data unencrypted on disk creates a practical exposure path if the host is multi-user, compromised, backed up insecurely, or the file is accidentally committed or copied.

Credential Access

High
Category
Privilege Escalation
Content
def get_api_key(required: bool = True) -> str | None:
    """
    Get API key from credentials.json or environment.
    
    Priority:
    1. SCOUT_API_KEY environment variable
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
This creates:
- A Crossmint smart wallet for your agent
- An API key for Scout API access
- Saves everything to credentials.json

After registration, fund your wallet with USDC to start buying.
No private key management needed - Crossmint handles wallet security.
Confidence
90% confidence
Finding
The script explicitly provisions an API credential and stores it in a predictable local file, which creates a credential access target for other local users, malware, or later agent actions. In the context of a purchasing skill, compromise of that key can facilitate unauthorized account actions and may be combined with stored shipping data to place fraudulent orders.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python search.py "wireless mouse"
    python search.py "laptop stand" --source amazon

API key is loaded automatically from credentials.json.
Run get_api_key.py first if you don't have one.
"""
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

No suspicious patterns detected.