T09 · Insecure Skill Coding Practices
Error
- Location
- launch.ts:116
- Finding
- Arbitrary Image URL Fetching Enables SSRF and Potential Data Disclosure<![CDATA[ ## Vulnerability Details **File Location**: `launch.ts:116-121`; related data flow at `launch.ts:194-201` and `launch.ts:214-234` **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unbounded remote content retrieval **Risk Level**: High ### Vulnerable Code ```ts async function loadImage(imagePath: string): Promise<Blob> { if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) { const res = await fetch(imagePath); if (!res.ok) throw new Error(`Failed to fetch image: ${res.status}`); return await res.blob(); } const resolved = path.resolve(imagePath); if (!fs.existsSync(resolved)) throw new Error(`Image not found: ${resolved}`); const buffer = fs.readFileSync(resolved); const ext = path.extname(resolved).toLowerCase(); const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : "image/jpeg"; return new Blob([buffer], { type: mime }); } ``` The function is invoked in dry-run mode: ```ts if (dryRun === "true") { console.log("✅ Dry run complete — parameters validated."); console.log(" Remove --dry-run to launch for real."); // Still validate image loads try { const blob = await loadImage(image); console.log(` Image loaded: ${blob.size} bytes (${blob.type})`); } catch (e: any) { console.error(` ❌ Image error: ${e.message}`); } return; } ``` In live mode, the downloaded response is passed to the external SDK: ```ts // Load image console.log("Uploading metadata to IPFS..."); const imageBlob = await loadImage(image); // Create SDK and launch const sdk = new PumpFunSDK(provider); const mintKeypair = Keypair.generate(); console.log(`Mint address: ${mintKeypair.publicKey.toBase58()}`); console.log("Sending transaction..."); try { const result = await sdk.createAndBuy( wallet, mintKeypair, { name, symbol, description, file: imageBlob, }, BigInt(Math.floor(buyAmountSol * LAMPORTS_PER_SOL)), slippageBps, ...[truncated 3616 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Prefer local image files or maintain an explicit allowlist of trusted HTTPS image hosts. 2. Reject plaintext HTTP and require HTTPS for all remote images. 3. Resolve the destination hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, documentation, and reserved IPv4 and IPv6 ranges. 4. Protect against DNS rebinding by ensuring the address used for the connection is the validated address. 5. Disable automatic redirects or validate the scheme, hostname, and resolved address of every redirect target. 6. Set strict connection and total-request timeouts with `AbortController`. 7. Stream responses and enforce a conservative maximum image size before buffering the complete body. 8. Permit only expected image content types and validate image signatures rather than trusting the `Content-Type` header or file extension. 9. Do not pass remotely fetched content to the SDK until all validation has completed. 10. Consider changing dry-run mode so it performs only local validation, or require explicit authorization before it makes any remote request. ]]>
