T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/hatchling.js:244
- Finding
- Unsanitized Question Content Is Transmitted as the Session Topic<![CDATA[ ## Vulnerability Details **File Location**: `scripts/hatchling.js:244-260` **Vulnerability Type**: Sensitive information exposure through inconsistent outbound sanitization **Risk Level**: High ### Vulnerable Code ```js const sessionRes = await fetch(`${RELAY_URL}/api/sessions`, { method: 'POST', headers: authHeaders(), body: JSON.stringify({ topic: question, buddy_id: buddyId }), }); const sessionData = await sessionRes.json(); if (!sessionRes.ok) { console.error('❌', sessionData.error); process.exit(1); } const sessionId = sessionData.session.id; console.log(` Session: ${sessionId}`); // Send message console.log('📤 Sending question...'); const msgRes = await fetch(`${RELAY_URL}/api/sessions/${sessionId}/messages`, { method: 'POST', headers: authHeaders(), body: JSON.stringify({ content: sanitizeContent(question) }), }); ``` ### Technical Analysis The `ask` command transmits the original question to the remote relay as the session `topic` before applying `sanitizeContent`. Although the subsequent message body uses `sanitizeContent(question)`, sanitizing that second transmission cannot undo the earlier disclosure. This contradicts the security claims in `README.md:98` and `SKILL.md:317`, which state that sensitive content is automatically sanitized before being sent. The sanitizer is intended to redact email addresses, phone numbers, public IP addresses, credentials, payment-card patterns, and certain other personal information. None of these protections apply to the session topic. The network communication is necessary for the Skill's declared question-and-answer functionality, but transmitting the same question twice—once unsanitized as metadata—exceeds the minimum data disclosure necessary. Session topics may also have broader visibility or longer retention than individual message content, such as appearing in dashboards, session lists, logs, analytics, or notifications. ### Attack Path 1. A user or AI agent invokes `ask` ...[truncated 1208 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Sanitize the question once before constructing any network request and reuse only the sanitized value: ```js const sanitizedQuestion = sanitizeContent(question); const sessionRes = await fetch(`${RELAY_URL}/api/sessions`, { method: 'POST', headers: authHeaders(), body: JSON.stringify({ topic: sanitizedQuestion, buddy_id: buddyId, }), }); const msgRes = await fetch(`${RELAY_URL}/api/sessions/${sessionId}/messages`, { method: 'POST', headers: authHeaders(), body: JSON.stringify({ content: sanitizedQuestion }), }); ``` 2. Prefer a generic session topic, such as `"ClawBuddy question"`, unless the user explicitly supplies a separate topic. 3. Apply a centralized outbound-data policy so every field containing user content passes through the same sanitizer. 4. Add automated tests that intercept all requests generated by `ask` and verify that no raw email address, credential, phone number, address, or other test secret appears in any URL, header, topic, or body. 5. Document that regex-based sanitization is best-effort and cannot guarantee removal of every sensitive value. 6. Consider server-side sanitization and data-minimization controls as defense in depth, including restricted metadata visibility and retention limits. ]]>
