Back to skill

Security audit

A.I. Cheese

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent paid-messaging tool, but it gives a remote server and unpinned runtime code too much practical authority over a funded wallet.

Install only if you are comfortable with a funded hot wallet being used for automatic paid messages. Use a dedicated low-balance wallet, avoid exposing a main wallet private key, review the server endpoint, and prefer a version with pinned dependencies plus explicit per-message confirmation and maximum spend limits.

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

Error
Location
scripts/ai-cheese.ts:88
Finding
Remote Payment Instructions Can Trigger Unrestricted USDC Transfers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai-cheese.ts`, lines 88-122; configurable server defined at line 14 **Vulnerability Type**: Insufficient validation of remotely supplied payment instructions **Risk Level**: High ### Vulnerable Code ```ts // Step 1: Get payment requirements console.log(`Sending to ${opts.to}...`); const firstTry = await fetch(`${SERVER}/api/v1/message`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(msg), }); if (firstTry.status === 200) { const result = await firstTry.json(); console.log(`✅ Delivered (no payment needed): ${result.messageId}`); return; } if (firstTry.status !== 402) { const err = await firstTry.json().catch(() => ({})); console.error(`❌ Error ${firstTry.status}: ${err.error || 'Unknown'}`); process.exit(1); } const requirements = await firstTry.json(); const payTo = requirements.accepts[0].payTo; const amount = BigInt(requirements.accepts[0].maxAmountRequired); const amountUsd = Number(amount) / 1e6; console.log(` Payment required: $${amountUsd.toFixed(2)} USDC to ${payTo}`); // Step 2: Pay USDC const usdc = new ethers.Contract(USDC_ADDRESS, USDC_ABI, wallet); console.log(` Sending USDC...`); const tx = await usdc.transfer(payTo, amount); ``` The source of the payment response can also be changed through an environment variable: ```ts const SERVER = process.env.AICHEESE_SERVER || 'https://aicheese.app'; ``` ### Technical Analysis The script treats an HTTP `402` response as sufficient authorization for an irreversible blockchain payment. Both the recipient address (`payTo`) and token amount (`maxAmountRequired`) are taken directly from the remote response and passed to the USDC contract without enforcing a local transaction policy. The implementation does not validate: - Whether `payTo` is a valid and expected recipient for the selected user. - Whether the requested amount mat ...[truncated 2659 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require an explicit local spending ceiling, such as `--max-payment-usdc`, for every paid message. Reject any response above that ceiling before constructing a transaction. 2. Display the validated recipient, exact amount, network, token contract, and message recipient, then require explicit operator confirmation unless a separately configured automation policy authorizes the payment. 3. Compare the requested payment with the directory price previously retrieved for the selected user. Reject unexplained discrepancies. 4. Validate the complete payment schema before accessing `accepts[0]`, including: - Recipient address format. - Non-negative amount and safe upper bounds. - Expected Base chain identifier. - Exact USDC contract address. - Supported x402 protocol version. - Expected payment recipient binding. 5. Require cryptographic authentication of payment requirements and verify that the authenticated identity is trusted. 6. Restrict `AICHEESE_SERVER` to an explicit allowlist. If custom servers are necessary, require a separate opt-in flag and clear warning that the server can direct payments. 7. Use a dedicated low-balance wallet or a smart account with per-transaction and cumulative spending limits. Do not expose a general-purpose funded wallet to this workflow. 8. Handle post-payment delivery failures explicitly and provide a reconciliation or refund process. Do not imply that payment confirmation guarantees message delivery. 9. Add tests using hostile `402` responses, including excessive amounts, malformed addresses, empty arrays, unexpected chains, wrong assets, and mismatched prices. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/ai-cheese.ts:1
Finding
Unpinned Runtime Dependency Execution Through npx<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai-cheese.ts`, lines 1-10; usage documented in `SKILL.md`, lines 17-26 and 88-90 **Vulnerability Type**: Unpinned third-party runtime and dependency resolution **Risk Level**: Medium ### Vulnerable Code ```ts #!/usr/bin/env npx tsx /** * A.I. Cheese CLI — Send paid messages to humans via aicheese.app * * Usage: * npx tsx ai-cheese.ts search [--location X] [--skills X] [--max-price X] * npx tsx ai-cheese.ts send --to <userId> --message "..." * npx tsx ai-cheese.ts replies [--since <timestamp>] * npx tsx ai-cheese.ts webhook --url <url> [--secret <secret>] */ ``` The documented execution pattern is: ```bash npx tsx scripts/ai-cheese.ts search --location london --skills spanish --max-price 0.50 npx tsx scripts/ai-cheese.ts send --to <userId> --message "What's the best cafe near you?" npx tsx scripts/ai-cheese.ts replies ``` The script also imports an external dependency: ```ts import { ethers } from 'ethers'; ``` No package manifest, committed lockfile, exact dependency versions, or integrity information is present in the audited project structure. ### Technical Analysis `npx tsx` can resolve and download `tsx` at execution time when no suitable local package is installed. Because the command does not specify an exact version and the project contains no lockfile, the effective executable can vary over time and between systems. The script also depends on `ethers`, but the audited package provides no declaration or lockfile fixing the version and transitive dependency graph. Resolution therefore depends on packages already available in the surrounding environment or on external installation steps that are not reproducibly defined by the Skill. This is particularly sensitive because the runtime executes in a process containing `AGENT_PRIVATE_KEY`. Any malicious code introduced through dependency resolution can read process environment variables, access files available to the us ...[truncated 1829 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a package manifest declaring exact audited versions of `tsx` and `ethers`. 2. Commit a lockfile containing the complete transitive dependency graph and integrity hashes. 3. Install dependencies with lockfile enforcement, such as `npm ci`, rather than resolving packages during each invocation. 4. Replace `npx tsx` in documentation and the shebang with a locally installed, lockfile-controlled executable. 5. Prevent `npx` from installing missing packages at runtime, for example by using an offline or no-install execution policy. 6. Use automated dependency scanning and review dependency updates before changing the lockfile. 7. Consider compiling the TypeScript script into a reviewed JavaScript artifact so normal execution does not require downloading a TypeScript runtime. 8. Run the Skill in an isolated environment exposing only the required variables. Avoid placing unrelated credentials in the same process environment. 9. Use a dedicated, minimally funded wallet for this Skill so dependency compromise cannot affect unrelated assets. 10. Pin the expected Node.js runtime version and verify release artifacts or package provenance where supported. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

Ae1

High
Category
analysis-evasion
Content
npx tsx scripts/ai-cheese.ts search --location london --skills spanish --max-price 0.50
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
npx tsx scripts/ai-cheese.ts search --location london --skills spanish --max-price 0.50
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
npx tsx scripts/ai-cheese.ts search --location london --skills spanish --max-price 0.50
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
npx tsx scripts/ai-cheese.ts search --location london --skills spanish --max-price 0.50
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises capabilities that require environment-variable access and outbound network access, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, this can lead to over-broad execution rights, making it easier for the skill to access sensitive credentials like the wallet private key and contact arbitrary remote services without informed approval.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill prominently describes sending paid messages and states that the bundled script handles payment automatically, but it does not provide a strong upfront warning that real funds will be spent. In an agent setting, this increases the chance of unintended or repeated spending, especially if the skill is invoked autonomously or by a user who does not realize blockchain payments are involved.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
Using `npx tsx` without a pinned package version allows execution to depend on whatever version is currently resolved from the package registry at runtime. This creates a supply-chain risk where a compromised, malicious, or breaking upstream release could execute arbitrary code in the agent environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
This unpinned `npx tsx` invocation has the same supply-chain exposure as the other occurrences: it may download and run an unexpected package version at runtime. Because the skill also uses a private key for payments, arbitrary code execution here could directly endanger funds and secrets.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
An unpinned `npx tsx` command in documentation can lead operators or agents to execute mutable third-party code. In this skill's context, that code could access the configured wallet private key and perform unintended transactions or exfiltrate secrets.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The setup instructs users to export a raw private key into an environment variable without any warning about secret handling, hot-wallet risk, or fund exposure. If logs, subprocesses, shell history, or malicious dependencies gain access to that variable, attackers could steal the key and drain associated assets.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
The generic run instruction again relies on unpinned `npx tsx`, preserving a runtime dependency confusion and supply-chain attack surface. Since this skill performs automated payments and uses environment-stored private keys, the risk is materially elevated beyond a normal documentation issue.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script automatically transfers USDC based solely on payment requirements returned by the remote server, with no user confirmation, recipient allowlist, chain/domain verification of the payment request, or maximum-spend guardrail. In this skill context, that is especially dangerous because the tool is explicitly designed to pay external parties, so a compromised server, misconfiguration via `AICHEESE_SERVER`, or malicious/buggy API response could trigger unintended irreversible on-chain payments.

Description-Behavior Mismatch

Low
Confidence
93% confidence
Finding
The manifest description lists directory search, sending paid messages, polling for replies, and webhook registration, but this file also exposes a `balance` command that inspects the agent wallet's USDC and ETH holdings. Checking on-chain wallet balances is related to payment operations, but it is still an additional user-facing capability not described in the manifest.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/ai-cheese.ts:14