T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/client.js:1
- Finding
- Bearer Token and User Content Can Be Sent to Arbitrary Configured Endpoints<![CDATA[ ## Vulnerability Details **File Location**: `scripts/client.js:1-20, 35-43`; `scripts/seedance.js:51-58, 67-73` **Vulnerability Type**: Unrestricted credential transmission to environment-controlled URLs **Risk Level**: High ### Vulnerable Code From `scripts/client.js:1-20`: ```js /** 从环境变量读取 TS_TOKEN 与 AIZNT_PROXY_URLS */ function loadClient() { const token = (process.env.TS_TOKEN || '').trim(); if (!token) { throw new Error('缺少 TS_TOKEN(天树对话凭证 ts_xxx,对应 skills.entries 的 apiKey)'); } const raw = process.env.AIZNT_PROXY_URLS; if (!raw || !String(raw).trim()) { throw new Error('缺少 AIZNT_PROXY_URLS(JSON 字符串,与 GET /miniapp/ai/chat/credentials 返回的 aiznt_proxy_urls 一致)'); } let urls; try { urls = typeof raw === 'string' ? JSON.parse(raw) : raw; } catch { throw new Error('AIZNT_PROXY_URLS 不是合法 JSON'); } if (!urls || typeof urls !== 'object') { throw new Error('AIZNT_PROXY_URLS 必须是对象'); } return { token, urls }; } ``` From `scripts/client.js:35-43`: ```js function authHeaders(token, extra = {}) { return { Authorization: `Bearer ${token}`, ...extra, }; } async function fetchJson(url, options = {}) { const res = await fetch(url, options); ``` From `scripts/seedance.js:51-58`: ```js const url = urls.seedance_content_generation_tasks; if (!url) throw new Error('AIZNT_PROXY_URLS 缺少 seedance_content_generation_tasks'); const body = bodyFromOpts(); const data = await fetchJson(url, { method: 'POST', headers: authHeaders(token, { 'Content-Type': 'application/json' }), body: JSON.stringify(body), }); ``` From `scripts/seedance.js:67-73`: ```js const tpl = urls.seedance_content_generation_tasks_fetch; if (!tpl) throw new Error('AIZNT_PROXY_URLS 缺少 seedance_content_generation_tasks_fetch'); const url = expandUrl(tpl, { task_id: taskId }); const data = await fetchJson(url, { headers: authHeaders(token) }); console.log(JSON.stringify(data, null, 2)); return; ``` ### Technical Analysis The Skill ...[truncated 2949 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse every configured endpoint using `new URL()` before use and reject malformed URLs. 2. Require the `https:` scheme. Reject `http:`, `file:`, and all other protocols. 3. Maintain an explicit allowlist of trusted Seedance proxy hostnames. Compare normalized `URL.hostname` values rather than using substring or suffix checks that can be bypassed. 4. Restrict ports to the expected secure service ports and reject embedded usernames, passwords, and unexpected URL fragments. 5. Verify that submit and fetch endpoints use approved origins. Prefer constructing fixed API paths from one trusted base URL instead of accepting complete URLs. 6. Add the bearer header only after endpoint validation succeeds. Authentication should fail closed for unapproved destinations. 7. Treat remotely synchronized endpoint configuration as untrusted until its authenticity and integrity have been verified. 8. URL-encode `task_id` with `encodeURIComponent()` before inserting it into a URL template. 9. Add automated tests confirming rejection of plain HTTP endpoints, attacker-controlled domains, deceptive subdomains, embedded credentials, unexpected ports, and unsupported schemes. 10. Consider using separate narrowly scoped credentials for task submission and polling, with short expiration periods and server-side audience restrictions. ]]>
