Back to skill

Security audit

openkrill

Security checks for vulnerabilities and agentic risk

Overview

This payments skill is not clearly malicious, but it needs Review because it can spend funds through broad x402 payment calls and also creates and reads disposable email accounts while storing their credentials locally.

Install only after reviewing whether you want an agent to spend from a thirdweb-backed wallet and create/read disposable inboxes. Use a low-funded wallet, require explicit approval for every payment, set and enforce spending caps outside this skill, avoid arbitrary x402 URLs, and do not use the disposable-email feature for sensitive accounts unless credential storage is fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fetch-with-payment.ts:44
Finding
Automatic Payment Requests Do Not Enforce a Mandatory Spending Limit or Destination Allowlist<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch-with-payment.ts:44-75` **Vulnerability Type**: Unrestricted payment destination and optional spending limit **Risk Level**: High ### Complete Code Snippet ```typescript // Build query parameters const params = new URLSearchParams(); params.set("url", options.url); params.set("method", options.method); if (options.from) { params.set("from", options.from); } if (options.maxValue) { params.set("maxValue", options.maxValue); } if (options.asset) { params.set("asset", options.asset); } if (options.chainId) { params.set("chainId", options.chainId); } const fetchUrl = `${THIRDWEB_API_BASE}/v1/payments/x402/fetch?${params.toString()}`; try { const response = await fetch(fetchUrl, { method: "POST", headers: { "Content-Type": "application/json", "x-secret-key": secretKey }, body: options.body ? JSON.stringify(options.body) : undefined }); ``` ### Technical Analysis The wrapper accepts an arbitrary target URL and forwards it to thirdweb's automatic x402 payment endpoint. The `maxValue` parameter is optional, so no local upper bound is applied when callers omit it. Although `assets/config-template.json` declares a default `maxPaymentUSD` value of `10.00`, the payment script does not read or enforce that configuration. The script also does not validate the target scheme, hostname, recipient, asset, chain, or requested payment amount before invoking the payment service. This is particularly risky in an agent environment because target URLs may originate from user input or service-discovery data. A malicious or compromised service can request a payment greater than the amount expected by the user. The code delegates the decision entirely to the remote payment service without an independent local policy or confirmation boundary. ### Attack Path 1. An attacker publishes or supplies an x402-compatible endpoint, potentially through a service catalog or untruste ...[truncated 893 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make `maxValue` mandatory at the payment boundary and reject calls where it is absent, malformed, zero, negative, or above a locally configured ceiling. 2. Enforce a conservative local default rather than relying on caller behavior. 3. Define the limit in the token's smallest unit and validate it with integer arithmetic to avoid unit or floating-point errors. 4. Restrict targets to HTTPS and maintain an explicit allowlist of approved hostnames and paths. 5. Reject embedded credentials, nonstandard ports, redirects to unapproved hosts, and private or loopback destinations. 6. Validate the expected chain, token contract, recipient, and amount before authorizing payment. 7. Present the final payment amount, asset, network, recipient, and target service to the user and require confirmation for new services or amounts above a low threshold. 8. Add cumulative session and daily spending limits, not only per-request limits. 9. Connect the declared `maxPaymentUSD` or `X402_MAX_PAYMENT` setting to actual enforcement and add tests proving that missing or excessive limits are rejected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/create-email.ts:24
Finding
Disposable Email Passwords and Bearer Tokens Are Persisted in a Plaintext File Without Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create-email.ts:24-31, 104-112, 165-177` **Vulnerability Type**: Plaintext credential storage **Risk Level**: High ### Complete Code Snippet ```typescript const MAIL_TM_API = "https://api.mail.tm"; const CREDENTIALS_FILE = ".agent-emails.json"; interface EmailAccount { address: string; password: string; token: string; accountId: string; createdAt: string; purpose?: string; } interface EmailCredentials { email_accounts: EmailAccount[]; } // Save credentials function saveCredentials(credentials: EmailCredentials): void { const filePath = getCredentialsPath(); fs.writeFileSync(filePath, JSON.stringify(credentials, null, 2)); } ``` Credential persistence occurs after account creation: ```typescript const account: EmailAccount = { address, password, token: tokenData.token, accountId: accountData.id, createdAt: new Date().toISOString() }; // Save to credentials file const credentials = loadCredentials(); credentials.email_accounts.push(account); saveCredentials(credentials); ``` ### Technical Analysis The application stores the email address, plaintext password, and active bearer token in `.agent-emails.json` under the current working directory. `fs.writeFileSync` is called without an explicit restrictive mode, ownership verification, symlink protection, or secure storage mechanism. Adding the filename to `.gitignore`, as recommended by the documentation, only reduces accidental version-control commits. It does not protect the file from other local processes, shared workspaces, backups, artifact collectors, compromised development tools, or overly permissive filesystem defaults. The stored inboxes may contain one-time passwords, account recovery messages, and verification links. Consequently, compromise of this local file can lead to compromise of other services registered using these addresses. ### Attack Path 1. A user or agent creates a disposable email accoun ...[truncated 1124 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store passwords in an operating-system credential manager or dedicated secrets service rather than in the project directory. 2. Do not persist bearer tokens when they can be obtained on demand from securely stored credentials. 3. If file storage is unavoidable, place the file in a user-specific configuration directory outside the repository. 4. Create the file atomically with mode `0600`, verify ownership, reject symbolic links, and verify that parent directories are not writable by untrusted users. 5. Apply restrictive permissions to existing files after validating ownership. 6. Separate account metadata from secrets so ordinary account-listing operations do not load credentials. 7. Provide explicit deletion and credential-rotation commands. 8. Document the sensitivity and retention period of inbox credentials instead of relying only on `.gitignore`. 9. Avoid retaining credentials after the disposable inbox is no longer needed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/create-email.ts:65
Finding
Email Authentication Passwords Are Generated with a Non-Cryptographic PRNG and Exposed to Process Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create-email.ts:65-85, 378-381` **Vulnerability Type**: Weak secret generation and sensitive-data logging **Risk Level**: Medium ### Complete Code Snippet ```typescript // Generate a random string for unique email addresses function generateRandomString(length: number = 10): string { const chars = "abcdefghijklmnopqrstuvwxyz0123456789"; let result = ""; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } // Generate a secure password function generatePassword(length: number = 16): string { const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%"; let result = ""; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } ``` The resulting secret is subsequently printed: ```typescript console.log("✓ Email account created successfully!\n"); console.log(` Address: ${result.account.address}`); console.log(` Password: ${result.account.password}`); console.log(` Token: ${result.account.token.substring(0, 20)}...`); ``` ### Technical Analysis `Math.random()` is not a cryptographically secure pseudorandom number generator and is unsuitable for authentication credentials. Its state and output are not designed to resist prediction. The function name and comment claim that the generated password is secure, but the underlying primitive does not provide that guarantee. The full password is also written to standard output. The first 20 characters of the bearer token are printed as well. Standard output may be captured by agent transcripts, CI systems, terminal logging, task runners, observability platforms, or shell-session recording. This creates an additional disclosure channel beyond the plaintext credentials file. ### Attack Path 1. The script creates a Mail.tm account and generates its password using `Math.ran ...[truncated 927 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `Math.random()` with Node.js `crypto.randomBytes()`, `crypto.randomInt()`, or a well-reviewed password-generation library pinned through a lockfile. 2. Ensure unbiased character selection, or encode sufficiently long random bytes using base64url. 3. Generate at least 128 bits of entropy for authentication secrets. 4. Do not print passwords or bearer-token fragments by default. 5. If users must retrieve a newly generated secret, require an explicit reveal option and write it only to an interactive terminal after warning about exposure. 6. Redact secrets in errors, traces, telemetry, and structured logs. 7. Add automated tests that reject use of `Math.random()` in credential-generation paths. 8. Rotate credentials already exposed through retained logs where practical. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:270
Finding
Documented npx Execution Can Download and Run Unpinned Third-Party Code with Access to Skill Secrets<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:270-280` **Vulnerability Type**: Unpinned runtime dependency and implicit remote package execution **Risk Level**: Medium ### Complete Code Snippet ```bash # Discover available services npx ts-node scripts/discover-services.ts # With pagination npx ts-node scripts/discover-services.ts --limit 50 --offset 0 # Use CDP facilitator npx ts-node scripts/discover-services.ts --facilitator "https://api.cdp.coinbase.com/platform/v2/x402" # Output as JSON for programmatic use npx ts-node scripts/discover-services.ts --json ``` The scripts also use an `npx`-based interpreter shebang, for example: ```typescript #!/usr/bin/env npx ts-node ``` ### Technical Analysis The project contains no reviewed package manifest or lockfile in the audited directory structure. The documentation repeatedly instructs users to execute TypeScript files through `npx ts-node`, and executable scripts use `#!/usr/bin/env npx ts-node`. Depending on the local npm/npx version and whether `ts-node` is already installed, `npx` may resolve and download package code at execution time. Without a lockfile and pinned package version, the effective code executed can change after this Skill has been reviewed. The downloaded process runs with the invoking user's permissions and inherits the environment. For wallet-related workflows, that environment may include `THIRDWEB_SECRET_KEY`. A compromised package release, registry account, resolution source, or package-install lifecycle path could therefore execute arbitrary code and access that secret. This finding represents an unsafe supply-chain execution pattern; the audit did not find evidence that the current `ts-node` package itself is malicious. ### Attack Path 1. A user follows the Skill documentation on a system without a verified local `ts-node` installation. 2. `npx` resolves and downloads a mutable package version from the configured package registry. 3. A compromised package, ...[truncated 818 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a `package.json` that pins reviewed versions of `typescript`, `ts-node`, and all required dependencies. 2. Commit a lockfile and install dependencies with a lockfile-enforcing command such as `npm ci`. 3. Invoke the verified local binary through a package script or `node_modules/.bin/ts-node`; do not permit `npx` to auto-install missing packages. 4. If `npx` remains necessary, use an exact reviewed version and disable interactive installation, while recognizing that pinning alone does not replace lockfile verification. 5. Consider compiling TypeScript during a controlled build and distributing JavaScript that runs directly with Node.js. 6. Use package integrity checks, dependency scanning, and registry allowlisting in deployment environments. 7. Run the Skill with a minimal environment and avoid exposing `THIRDWEB_SECRET_KEY` to commands that do not need it. 8. Document reproducible installation and verification procedures. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (133)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill claims to handle x402 micropayments, but also includes unrelated disposable email account creation, token retrieval, inbox access, and local credential storage. This scope expansion can mislead agents into performing account-creation and credential-handling actions the user did not authorize under the guise of a payments skill.

Ae1

High
Category
analysis-evasion
Content
npx ts-node scripts/discover-services.ts
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
npx ts-node scripts/discover-services.ts
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
npx ts-node scripts/discover-services.ts
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
npx ts-node scripts/discover-services.ts
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
"step": 2,
        "action": "Set environment variable",
        "command": "export THIRDWEB_SECRET_KEY='your-key-here'",
        "description": "Add to .env.local or shell profile"
      },
      {
        "step": 3,
Confidence
97% confidence
Finding
The instructions explicitly recommend adding `THIRDWEB_SECRET_KEY` to `.env.local` or a shell profile, normalizing storage of a payment-capable secret in plaintext developer-managed locations. In the context of a micropayments skill, compromise of this credential could enable unauthorized API usage, wallet control, spending, and downstream financial abuse.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The file implements disposable email account creation and inbox management, which is unrelated to the stated skill purpose of x402 micropayments. Capability mismatch is dangerous because it can hide unauthorized account creation, OTP interception, and identity-abuse functionality inside a package users would not reasonably expect to manipulate email accounts.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The code actively creates disposable addresses, authenticates to a third-party mailbox service, refreshes tokens, lists messages, and reads message contents. In the context of a micropayments skill, this unjustified capability can be abused to register throwaway accounts and capture verification emails or recovery links, significantly expanding the skill's power beyond payments into covert account operations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill requires sensitive capabilities (`env` access to `THIRDWEB_SECRET_KEY` and unrestricted network access) but does not declare an explicit tool scope such as `permissions` or `allowed-tools`. That makes the operational boundary ambiguous and increases the chance an agent can use broader tools than intended while handling payments and external API calls.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill promotes automatic payment flows and opening funding links but does not clearly warn that these actions may spend real funds or send users to third-party payment pages. In an autonomous-agent context, that can lead to unintended purchases or social-engineering-like redirection under the authority of the skill.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Query the Bazaar to see what's available (no auth required)
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50"
```

## Prerequisites
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Query the Bazaar to see what's available (no auth required)
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50"
```

## Prerequisites
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Query the Bazaar to see what's available (no auth required)
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50"
```

## Prerequisites
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Query the Bazaar to see what's available (no auth required)
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50"
```

## Prerequisites
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Query the Bazaar to see what's available (no auth required)
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50"
```

## Prerequisites
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Query the Bazaar to see what's available (no auth required)
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50"
```

## Prerequisites
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Discovery tips:**
- Check for `x402.` subdomain (e.g., `x402.browserbase.com`)
- Check for `/x402/` in the path (e.g., `/v1/x402/search`)
- Hit the x402 root URL for endpoint listing (e.g., `curl https://x402.browserbase.com/`)

## Core Workflow
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
Use the thirdweb API directly (recommended):

```bash
curl -s -X POST https://api.thirdweb.com/v1/wallets/server \
  -H "Content-Type: application/json" \
  -H "x-secret-key: $THIRDWEB_SECRET_KEY" \
  -d '{"identifier": "x402-agent-wallet"}'
Confidence
78% confidence
Finding
This example sends the sensitive `THIRDWEB_SECRET_KEY` to thirdweb to create a server wallet. While this may be intended, it is high-trust external transmission of a secret-bearing request and can create managed wallets capable of spending funds if an agent executes it without strict authorization.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Browserbase - Create browser session
curl -s -X POST "https://api.thirdweb.com/v1/payments/x402/fetch?url=https://x402.browserbase.com/browser/session/create&method=POST" \
  -H "Content-Type: application/json" \
  -H "x-secret-key: $THIRDWEB_SECRET_KEY" \
  -d '{"browserSettings": {"viewport": {"width": 1920, "height": 1080}}}'
Confidence
80% confidence
Finding
This call transmits a secret-authenticated payment request to thirdweb that can cause paid actions against Browserbase. Because it combines external transmission, authenticated access, and monetary effect, it is more dangerous than ordinary network usage in this skill context.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/create-email.ts:133