T09 · Insecure Skill Coding Practices
- Location
SKILL.md:1225- Finding
Unrestricted Webhook Destinations Permit Sensitive Event Disclosure and SSRF
- Content
View full analysis
{ const relevant = webhooks.filter((wh) => wh.events.includes(event.type) || wh.events.includes("*") ); await Promise.allSettled( relevant.map((wh) => fetch(wh.url, { method: "POST", headers: { "Content-Type": "application/json", "X-Webhook-Secret": wh.secret, "X-Event-Type": event.type, "X-Event-ID": event.id, }, body: JSON.stringify(event), }) ) ); } ``` ### Technical Analysis The generated implementation accepts an unrestricted `WebhookConfig.url` and sends the complete event object to that destination. No controls enforce HTTPS, restrict destinations to approved origins, block private or link-local network ranges, revalidate DNS results, disable redirects, or limit the transmitted payload. The documented `BaseEvent` schema permits arbitrary payload fields, while example events include personal data such as user email addresses. Consequently, the request may transmit sensitive application or user data beyond the intended trust boundary. The implementation also places the shared webhook secret directly in the `X-Webhook-Secret` header instead of using it locally to calculate a message authentication code. A receiving endpoint therefore learns the reusable secret. The `events` list supports the wildcard `"*"`, increasing the potential data scope available to a malicious or incorrectly confi ...[truncated 1959 chars]- Remediation
View remediation
