T09 · Insecure Skill Coding Practices
- Location
- scripts/generate-pearls.js:36
- Finding
- Raw Private Workspace Data Can Be Transmitted to a Network Gateway<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-pearls.js:36-45, 85-99, 120-166, 251-269, 285-300`; related destination validation in `scripts/lib/url-utils.js:24-42` **Vulnerability Type**: Sensitive-data exposure through insufficient destination restrictions and post-transmission sanitization **Risk Level**: High ### Vulnerable Code ```javascript // Security: Only allow localhost gateways for pearl generation // Pearl generation reads sensitive workspace files (MEMORY.md, AGENTS.md, TOOLS.md) // and sends content to the gateway. Remote gateways = data exfiltration risk. if (!isLocalhostUrl(GATEWAY_URL)) { console.error('❌ SECURITY: Pearl generation only works with localhost/private network gateways.'); console.error(` GATEWAY_URL (${GATEWAY_URL}) appears to be a remote host.`); console.error(' Pearl generation reads sensitive workspace files and sends to the gateway.'); console.error(' Use a local gateway (127.0.0.1, localhost, 10.x.x.x, 192.168.x.x).'); process.exit(1); } ``` ```javascript async function callGateway(messages) { const res = await fetch(`${GATEWAY_URL}/v1/chat/completions`, { method: 'POST', headers: { 'Authorization': `Bearer ${GATEWAY_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: MODEL, messages, max_tokens: 8192, }), }); if (!res.ok) { const errText = await res.text(); throw new Error(`Gateway error: ${res.status} ${errText}`); } const data = await res.json(); return data.choices?.[0]?.message?.content || ''; } ``` ```javascript const memory = readFileIfExists(path.join(WORKSPACE, 'MEMORY.md')) || readFileIfExists(path.join(WORKSPACE, 'memories', 'MEMORY.md')); if (memory) { const section = `## MEMORY.md (Long-term Memory)\n${memory}`; sections.push(section); totalChars += section.length; } const userMemory = readFileIfExists(path.join(WORKSPACE, 'USER.md')) || readFileIfExists(path.j ...[truncated 3460 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Restrict the default gateway policy to literal loopback destinations only: - `127.0.0.0/8` - `::1` - `localhost` 2. Do not treat RFC 1918 or `.local` destinations as equivalent to localhost. 3. Require explicit, informed user approval before transmitting workspace content to any non-loopback destination. 4. Display the resolved destination, selected source files, and approximate payload size before transmission. 5. Exclude `USER.md`, raw memory, and agent configuration by default. Prefer an explicit allowlist of reviewed files. 6. Perform deterministic local redaction before constructing the network request. Do not rely on an LLM prompt as the privacy boundary. 7. Add secret scanning for API keys, tokens, passwords, private keys, URLs, IP addresses, and personal identifiers. 8. Provide a dry-run mode that writes the exact outgoing payload to a review file without sending it. 9. Separate gateway credentials for private-data processing from general gateway credentials and minimize their scope. 10. Require HTTPS and certificate validation for any explicitly approved non-loopback gateway. ]]>
