Back to skill

Security audit

Aavegotchi 3D Renderer

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says for Aavegotchi rendering, but its helper script trusts renderer-provided download URLs too broadly, which could make the user's machine fetch arbitrary or oversized remote content.

Review before installing. Use this only in an environment where outbound network requests are acceptable, avoid running it on hosts with sensitive internal HTTP services, and prefer a restricted output directory. The skill would be safer if it validated artifact URLs against expected Aavegotchi/CDN hosts and enforced timeouts and download size limits.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/render-gotchi-bypass.mjs:250
Finding
Unrestricted Renderer-Controlled Artifact URLs Enable Blind SSRF and Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/render-gotchi-bypass.mjs`, lines 250-257, 335-341, and 353-359 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unbounded resource consumption **Risk Level**: Medium ### Vulnerable Code ```js async function downloadFile(url, filePath) { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to download ${url} (${response.status})`); } const bytes = Buffer.from(await response.arrayBuffer()); fs.writeFileSync(filePath, bytes); return filePath; } ``` ```js if (proxyUrls.PNG_Full && finalAvailability?.PNG_Full?.exists === true) { const fullUrl = proxyUrls.PNG_Full.startsWith("http") ? proxyUrls.PNG_Full : `${DAPP_BASE}${proxyUrls.PNG_Full}`; artifacts.fullPngPath = path.join(options.outDir, `gotchi-${tokenId}-full.png`); await downloadFile(fullUrl, artifacts.fullPngPath); artifacts.fullPngUrl = fullUrl; } ``` ```js if (proxyUrls.PNG_Headshot && finalAvailability?.PNG_Headshot?.exists === true) { const headshotUrl = proxyUrls.PNG_Headshot.startsWith("http") ? proxyUrls.PNG_Headshot : `${DAPP_BASE}${proxyUrls.PNG_Headshot}`; artifacts.headshotPngPath = path.join(options.outDir, `gotchi-${tokenId}-headshot.png`); await downloadFile(headshotUrl, artifacts.headshotPngPath); artifacts.headshotPngUrl = headshotUrl; } ``` ### Technical Analysis The `proxyUrls.PNG_Full` and `proxyUrls.PNG_Headshot` values originate from the remote renderer API response. When either value begins with `"http"`, the script passes it directly to `fetch()` without validating its protocol, hostname, resolved address, port, credentials, or redirect destination. A compromised or malicious renderer response can therefore instruct the script to send requests to arbitrary HTTP resources reachable from the execution environment. Potential targets include loopback services, private network hosts, link-local services, and cloud metadata endpoints. Red ...[truncated 3032 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse every artifact URL using `new URL()` rather than accepting values based on `startsWith("http")`. 2. Require HTTPS and reject URLs containing embedded credentials, unexpected ports, unsupported schemes, or malformed hostnames. 3. Maintain an explicit allowlist of expected Aavegotchi and renderer CDN hostnames. Treat relative URLs as relative to `DAPP_BASE`, but still validate the resulting URL. 4. Resolve destination hostnames and reject loopback, private, link-local, multicast, reserved, and cloud metadata address ranges for both IPv4 and IPv6. 5. Disable automatic redirects where possible. If redirects are required, validate the scheme, hostname, port, and resolved address at every redirect hop. 6. Add request timeouts with `AbortController`. 7. Check `Content-Type` against expected image media types before saving PNG artifacts. 8. Enforce a conservative maximum response size using `Content-Length` where available and a byte-counting streaming limit regardless of that header. 9. Stream responses to a temporary file rather than buffering the entire response in memory. Atomically rename the file only after validation succeeds, and delete partial files on failure. 10. Apply output-directory quotas or confirm sufficient available storage before downloading. 11. Consider verifying PNG signatures and image structure before treating downloaded files as valid artifacts. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (6)

Ae1

High
Category
analysis-evasion
Content
node scripts/render-gotchi-bypass.mjs --token-id 6741
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/render-gotchi-bypass.mjs --token-id 6741
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill performs network operations against external services but does not declare any explicit tool scope or permissions. This weakens reviewability and policy enforcement, because an agent may invoke outbound requests without a clearly documented authorization boundary.

External Transmission

Medium
Category
Data Exfiltration
Content
1. Extract `tokenId` from direct input or inventory URL.
2. Query Goldsky Base core subgraph:
`https://api.goldsky.com/api/public/project_cmh3flagm0001r4p25foufjtt/subgraphs/aavegotchi-core-base/prod/gn`
3. Derive hash in renderer format:
`<Collateral>-<EyeShape>-<EyeColor>-<Body>-<Face>-<Eyes>-<Head>-<RightHand>-<LeftHand>-<Pet>`
4. Kick off render with `POST https://www.aavegotchi.com/api/renderer/batch` using:
Confidence
84% confidence
Finding
The skill sends user-supplied token identifiers or inventory-derived data to third-party endpoints at Goldsky and aavegotchi.com. This is an external data transmission risk because user input and derived metadata leave the local trust boundary, and the skill does not describe minimization, consent, or validation around those transfers.

External Transmission

Medium
Category
Data Exfiltration
Content
import path from "node:path";

const GOLDSKY_ENDPOINT =
  "https://api.goldsky.com/api/public/project_cmh3flagm0001r4p25foufjtt/subgraphs/aavegotchi-core-base/prod/gn";
const DAPP_BASE = "https://www.aavegotchi.com";
const RENDER_TYPES = ["PNG_Full", "PNG_Headshot", "GLB_3DModel"];
const DEFAULT_POLL_ATTEMPTS = 18;
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The skill instructs saving raw JSON responses and rendered image artifacts to local disk without warning the user or defining retention limits. Even if the data is not highly sensitive in normal use, silent persistence can expose user-linked URLs, token identifiers, metadata, or downloaded content to later unintended access on shared systems.

Static analysis

No suspicious patterns detected.