Back to skill

Security audit

Clawphunks

Security checks for vulnerabilities and agentic risk

Overview

This NFT skill matches its stated purpose, but it asks agents to handle real wallet keys and sign payments without enough local safeguards.

Review before installing or deploying. Use only a low-balance wallet, do not reuse a primary wallet private key, verify every USDC amount and recipient before signing, avoid running mutable remote scripts blindly, and fix the facilitator, Supabase policy, and dependency issues before operating this as a public service.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/server.ts:634
Finding
Unauthenticated Facilitator Endpoint Allows Unauthorized Gas Sponsorship<![CDATA[ ## Vulnerability Details **File Location**: `src/server.ts:634-645`, `src/facilitator.ts:218-259` **Vulnerability Type**: Missing authentication and server-side authorization **Risk Level**: High ### Vulnerable Code ```ts // src/server.ts:634-645 app.post('/facilitator/settle', async (req, res) => { try { const { paymentPayload, paymentRequirements } = req.body; const result = await facilitatorSettle(paymentPayload, paymentRequirements); res.json(result); } catch (err: any) { res.json({ success: false, error: err.message, }); } }); ``` ```ts // src/facilitator.ts:218-259 export async function settle( paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements ): Promise<SettleResponse> { try { const { walletClient, publicClient } = getSignerWallet(); const { authorization, signature } = paymentPayload.payload; const { v, r, s } = parseSignature(signature); console.log('[facilitator] Settling payment...'); console.log(` From: ${authorization.from}`); console.log(` To: ${authorization.to}`); console.log(` Value: ${authorization.value} (${Number(authorization.value) / 1e6} USDC)`); const hash = await walletClient.writeContract({ address: USDC_ADDRESS, abi: TRANSFER_WITH_AUTH_ABI, functionName: 'transferWithAuthorization', args: [ authorization.from as `0x${string}`, authorization.to as `0x${string}`, BigInt(authorization.value), BigInt(authorization.validAfter), BigInt(authorization.validBefore), authorization.nonce as `0x${string}`, v, r, s, ], }); console.log(`[facilitator] Tx submitted: ${hash}`); const receipt = await publicClient.waitForTransactionReceipt({ hash }); if (receipt.status === 'success') { console.log(`[facilitator] ✓ Payment settled: ${hash}`); return { success: true, txHash: hash }; } else { console. ...[truncated 2310 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make the facilitator endpoints private and accessible only to the payment middleware or a dedicated trusted service. 2. Require authenticated, integrity-protected requests, such as mutually authenticated TLS or an HMAC signature with timestamp and nonce. 3. Invoke strict verification from inside `settle()` rather than relying on callers to invoke `/verify` first. 4. Ignore caller-provided merchant requirements where possible. Construct the expected network, asset, recipient, and amount from trusted server configuration. 5. Require the authorization recipient to equal the configured `PAYMENT_RECIPIENT`. 6. Require the token contract to equal the supported Base USDC contract and require the exact configured mint amount. 7. Bind each settlement to a short-lived, server-generated payment request identifier. 8. Store and reject previously settled nonces before broadcasting transactions. 9. Add per-client and global rate limits, gas-spending limits, monitoring, and emergency circuit breakers. 10. Use a dedicated facilitator wallet with only the minimum gas balance required for expected operations. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
mcp/src/index.ts:219
Finding
Generated Mint Scripts Sign Unbounded Server-Controlled Payment Terms<![CDATA[ ## Vulnerability Details **File Location**: `mcp/src/index.ts:219-242`, `mcp/src/index.ts:356-369`, `src/server.ts:92-115` **Vulnerability Type**: Insufficient validation before signing a token-transfer authorization **Risk Level**: High ### Vulnerable Code ```ts // mcp/src/index.ts:219-242 const accept = paymentReqs.accepts[0]; // Step 2: Sign EIP-3009 TransferWithAuthorization const nonce = keccak256(encodePacked(['address', 'uint256'], [account.address, BigInt(Date.now())])); const now = Math.floor(Date.now() / 1000); const validAfter = BigInt(now - 5); const validBefore = BigInt(now + 60); const signature = await walletClient.signTypedData({ domain: { name: accept.extra.name, version: accept.extra.version, chainId: 8453, verifyingContract: USDC_BASE }, types: { TransferWithAuthorization: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'validAfter', type: 'uint256' }, { name: 'validBefore', type: 'uint256' }, { name: 'nonce', type: 'bytes32' }, ], }, primaryType: 'TransferWithAuthorization', message: { from: account.address, to: accept.payTo, value: BigInt(accept.maxAmountRequired), validAfter, validBefore, nonce }, }); // Step 3: Build X-PAYMENT header const paymentPayload = { x402Version: 1, scheme: 'exact', network: 'base', payload: { signature, authorization: { from: account.address, to: accept.payTo, value: accept.maxAmountRequired, validAfter: validAfter.toString(), validBefore: validBefore.toString(), nonce } }, }; ``` The second generated MCP script repeats the same behavior: ```ts // mcp/src/index.ts:356-369 const accept = paymentReqs.accepts[0]; console.log('Step 2: Signing USDC payment...'); const nonce = keccak256(encodePacked(['address', 'uint256'], [account.address, BigInt(Date.now())])); const now = Math.floor(Date.now() / 1000); const signature = await baseWallet.signTypedData({ domain: { name: accept.extra.name, version: a ...[truncated 3034 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the expected merchant recipient in trusted local code or configuration. 2. Define a local maximum amount of exactly 1,990,000 USDC base units and reject any larger or different amount. 3. Validate that the asset is Base USDC at `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`. 4. Validate the x402 version, scheme, network, chain ID, EIP-712 domain name, domain version, and verifying contract. 5. Require the initial response to have HTTP status 402 before parsing payment requirements. 6. Validate the response against a strict schema and reject missing, duplicate, or unexpected payment options. 7. Display the recipient, token, amount, network, and expiration to the user and require explicit confirmation before signing. 8. Avoid silently choosing `accepts[0]`; select only an entry satisfying all locally defined constraints. 9. Apply the same checks to every copy of the generated code in `src/server.ts` and `mcp/src/index.ts`. 10. Add automated tests using malicious payment responses to ensure excessive amounts and changed recipients are rejected. ]]>

T03 · Remote Payload Retrieval and Execution

Warning
Location
integrations/langchain/clawphunks_tool.py:115
Finding
Agent Integrations Retrieve Mutable Executable Instructions from an External Domain<![CDATA[ ## Vulnerability Details **File Location**: `integrations/langchain/clawphunks_tool.py:22,115-127`, `integrations/agentkit/clawphunks_action.ts:22,94-110` **Vulnerability Type**: Unverified remote payload retrieval **Risk Level**: Medium ### Vulnerable Code ```python # integrations/langchain/clawphunks_tool.py:22 SKILLS_URL = "https://chainhost.online/clawphunks/skills" ``` ```python # integrations/langchain/clawphunks_tool.py:115-127 def _run(self, query: str = "") -> str: """Get skills/scripts.""" try: response = requests.get(SKILLS_URL) if response.status_code == 200: return response.text return f"Error: {response.status_code}" except Exception as e: return f"Error: {str(e)}" async def _arun(self, query: str = "") -> str: return self._run(query) ``` ```ts // integrations/agentkit/clawphunks_action.ts:94-110 export const clawphunksSkillsAction: ActionDefinition = { name: 'clawphunks_skills', description: 'Get complete executable scripts for listing, buying, transferring, and rescuing ClawPhunks on L1.', schema: z.object({}), handler: async () => { const response = await fetch(SKILLS_URL); if (!response.ok) { throw new Error(`Failed to fetch skills: ${response.status}`); } return await response.json(); }, }; ``` ### Technical Analysis Both integrations advertise a tool that returns complete executable wallet and trading scripts, but obtain those scripts from `chainhost.online` at invocation time. The response is returned directly to the agent without: - Pinning a specific immutable version. - Verifying a cryptographic digest or signature. - Validating the response against an approved instruction set. - Separating remote content from trusted tool instructions. - Warning the agent that the content is untrusted and mutable. The external domain is separate from the primary mint API domain. Its content can change after package review without any change t ...[truncated 1492 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle audited scripts in the package instead of downloading them at runtime. 2. If remote distribution is required, use immutable versioned URLs and verify a pinned SHA-256 digest or publisher signature. 3. Reject redirects to unexpected hosts and apply connection and response-size limits. 4. Parse the response using a strict schema and expose only approved structured fields. 5. Mark all remotely retrieved content as untrusted data rather than authoritative agent instructions. 6. Do not describe unverified remote content as ready-to-run executable code. 7. Require explicit human review and confirmation before any returned code can initiate wallet operations. 8. Prefer the audited primary-domain API over a separate mutable instruction host. 9. Record the fetched artifact version and digest for auditability. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
supabase/schema.sql:58
Finding
Supabase Write Policy Is Not Restricted to the Service Role<![CDATA[ ## Vulnerability Details **File Location**: `supabase/schema.sql:58-64` **Vulnerability Type**: Overly permissive row-level security policy **Risk Level**: High ### Vulnerable Code ```sql -- ============================================================================ -- RLS -- ============================================================================ ALTER TABLE items ENABLE ROW LEVEL SECURITY; CREATE POLICY "Public read items" ON items FOR SELECT USING (true); CREATE POLICY "Service write items" ON items FOR ALL USING (true) WITH CHECK (true); ``` ### Technical Analysis The policy named `"Service write items"` is not scoped with a `TO service_role` clause. PostgreSQL policies without a role restriction apply to all roles that otherwise have the relevant table privilege. The policy covers `FOR ALL` and uses unconditional `USING (true)` and `WITH CHECK (true)` expressions. Consequently, any Supabase role with insert, update, or delete privileges on `items` can pass row-level security for every row. The policy name has no security effect. Whether an anonymous client can immediately exploit this depends on the table grants configured in the deployed Supabase project, which are not shown in the repository. Nevertheless, the schema itself fails to enforce its stated service-only boundary and becomes exploitable whenever write privileges are granted to `anon`, `authenticated`, or another untrusted role. ### Attack Path 1. An attacker identifies the project's public Supabase URL and obtains an allowed client credential. 2. The corresponding role has or later receives write privileges on the `items` table or execution rights for an insufficiently restricted database function. 3. The unconditional `FOR ALL` policy authorizes access to every inventory row. 4. The attacker changes `minted`, `minted_to`, `tx_hash`, `data_uri`, or deletes records. 5. The mint service consumes corrupted inventory state or attacker-modified inscription data. ### Impact A ...[truncated 585 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Scope privileged write policies explicitly: ```sql DROP POLICY IF EXISTS "Service write items" ON items; CREATE POLICY "Service write items" ON items FOR ALL TO service_role USING (true) WITH CHECK (true); ``` 2. Revoke direct write access from public roles: ```sql REVOKE INSERT, UPDATE, DELETE, TRUNCATE ON TABLE items FROM anon, authenticated; ``` 3. Grant public roles only the minimum required `SELECT` access, if public inventory reads are intentional. 4. Review and restrict `EXECUTE` privileges on `claim_random_item` and `finalize_mint`. 5. Use `SECURITY DEFINER` functions only when necessary, set a safe `search_path`, and validate every permitted state transition. 6. Prevent arbitrary changes to immutable fields such as `token_id` and `data_uri`. 7. Add database constraints or triggers ensuring finalized mints cannot be returned to the unminted state without an explicit privileged recovery process. 8. Verify deployed table grants in addition to RLS policies; both layers must enforce least privilege. 9. Add audit logging for inventory mutations and alerts for unexpected bulk updates or deletions. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (72)

Credential Access

High
Category
Privilege Escalation
Content
## Run Server

```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cp .env.example .env
# Edit .env with your keys
npm run dev
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill claims minting and trading, yet the file mainly documents generic transaction construction and use of a signer key without clearly constrained permissions. In the context of blockchain actions, vague capability descriptions are dangerous because they can normalize giving a skill broad signing authority for actions beyond what users expect.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill claims minting and trading, yet the file mainly documents generic transaction construction and use of a signer key without clearly constrained permissions. In the context of blockchain actions, vague capability descriptions are dangerous because they can normalize giving a skill broad signing authority for actions beyond what users expect.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The skill claims minting and trading, yet the file mainly documents generic transaction construction and use of a signer key without clearly constrained permissions. In the context of blockchain actions, vague capability descriptions are dangerous because they can normalize giving a skill broad signing authority for actions beyond what users expect.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims minting and trading, yet the file mainly documents generic transaction construction and use of a signer key without clearly constrained permissions. In the context of blockchain actions, vague capability descriptions are dangerous because they can normalize giving a skill broad signing authority for actions beyond what users expect.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
The skill claims minting and trading, yet the file mainly documents generic transaction construction and use of a signer key without clearly constrained permissions. In the context of blockchain actions, vague capability descriptions are dangerous because they can normalize giving a skill broad signing authority for actions beyond what users expect.

Known Vulnerable Dependency: express-rate-limit==8.2.1 — 1 advisory(ies): CVE-2026-30827 (express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting o)

High
Category
Supply Chain
Confidence
91% confidence
Finding
express-rate-limit 8.2.1 is reported vulnerable to bypass when clients use IPv4-mapped IPv6 addresses, which can defeat per-client throttling. Because the MCP SDK includes HTTP server components, this weakness can materially reduce protections against brute force, abuse, or resource exhaustion if rate limiting is relied upon.

Known Vulnerable Dependency: fast-uri==3.1.0 — 7 advisory(ies): CVE-2026-13676 (fast-uri vulnerable to host confusion via failed IDN canonicalization); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +4 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
fast-uri 3.1.0 has multiple URI parsing and canonicalization advisories, including host confusion and SSRF-related cases. This is a real concern when untrusted URLs are parsed for allowlisting, routing, callback validation, or outbound fetch decisions, although the lockfile alone does not show direct use of those code paths.

Known Vulnerable Dependency: hono==4.12.5 — 16 advisory(ies): CVE-2026-56762 (Hono missing validation of cookie name on write path in setCookie()); CVE-2026-47676 (Hono: app.mount() strips mount prefix using undecoded path, causing incorrect ro); CVE-2026-47675 (Hono: Cookie helper does not sanitize sameSite and priority, allowing Set-Cookie) +13 more

High
Category
Supply Chain
Confidence
88% confidence
Finding
hono 4.12.5 is listed with many advisories affecting cookies, routing, and request handling. Since this package underpins the server stack brought in by the MCP SDK, unresolved framework flaws can expose the service to bypasses, header/cookie issues, or routing mistakes even if the application code itself appears minimal.

Known Vulnerable Dependency: ip-address==10.0.1 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
80% confidence
Finding
ip-address 10.0.1 is reported vulnerable to parsing inconsistencies and XSS in HTML-emitting helpers. The parsing issue is more relevant here because this library is used by express-rate-limit; inconsistent IP interpretation can undermine security decisions such as client identification or allow/deny logic.

Known Vulnerable Dependency: path-to-regexp==8.3.0 — 2 advisory(ies): CVE-2026-4923 (path-to-regexp vulnerable to Regular Expression Denial of Service via multiple w); CVE-2026-4926 (path-to-regexp vulnerable to Denial of Service via sequential optional groups)

High
Category
Supply Chain
Confidence
84% confidence
Finding
path-to-regexp 8.3.0 has reported ReDoS/DoS weaknesses in route pattern processing. In a server context, expensive route matching can let remote attackers consume CPU and degrade availability if crafted paths hit vulnerable patterns or framework internals.

Missing User Warnings

High
Confidence
97% confidence
Finding
The documentation instructs use of a wallet private key and describes minting and trading flows for irreversible blockchain transactions, but it does not prominently warn about key-handling risk, transaction finality, cross-chain payment complexity, or the possibility of permanent fund loss. In this context, the omission is especially dangerous because the skill is designed for AI agents and directly interfaces with a signing wallet, making user misunderstanding more likely to result in real financial loss.

Credential Access

High
Category
Privilege Escalation
Content
// Main
const privateKey = process.env.AGENT_PRIVATE_KEY;
if (!privateKey) { console.error('Set AGENT_PRIVATE_KEY in .env'); process.exit(1); }

const account = privateKeyToAccount(privateKey);
console.log('Wallet:', account.address);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// Main
const privateKey = process.env.AGENT_PRIVATE_KEY;
if (!privateKey) { console.error('Set AGENT_PRIVATE_KEY in .env'); process.exit(1); }

const account = privateKeyToAccount(privateKey);
console.log('Wallet:', account.address);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// Main
const privateKey = process.env.AGENT_PRIVATE_KEY;
if (!privateKey) { console.error('Set AGENT_PRIVATE_KEY in .env'); process.exit(1); }

const account = privateKeyToAccount(privateKey);
console.log('Wallet:', account.address);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// Main
const privateKey = process.env.AGENT_PRIVATE_KEY;
if (!privateKey) { console.error('Set AGENT_PRIVATE_KEY in .env'); process.exit(1); }

const account = privateKeyToAccount(privateKey);
console.log('Wallet:', account.address);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
mcp/src/index.ts:257

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/server.ts:147

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
public/llms.txt:34

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
public/skill.md:221

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:221

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
src/server.ts:605