T09 · Insecure Skill Coding Practices
- Location
- scripts/fulfill.js:115
- Finding
- Unvalidated API origins can expose credentials, access tokens, and customer data<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/fulfill.js:79-80` - `scripts/fulfill.js:115-147` - `scripts/rebuild-mapping.js:37-40` - `scripts/rebuild-mapping.js:90-114` - `scripts/cj-api.js:15-34` - `scripts/cj-api.js:43-61` - `scripts/woo-api.js:14-19` **Vulnerability Type**: Unvalidated security-sensitive endpoint configuration **Risk Level**: High ### Vulnerable Code From `scripts/fulfill.js`: ```js function wooCfg() { const cfg = JSON.parse(fs.readFileSync(WOO_API_PATH, 'utf8')); const base = cfg.url.replace(/\/$/, '') + '/wp-json/wc/v3'; const auth = { username: cfg.consumerKey, password: cfg.consumerSecret }; return { base, auth }; } ``` ```js async function cjEnsureToken() { const cfg = cjCfg(); const now = Date.now(); const exp = Number(cfg.tokenExpiry || 0); if (cfg.accessToken && exp && now < exp - 10 * 60 * 1000) return cfg.accessToken; console.log(' 🔑 Refreshing CJ access token...'); const baseUrl = (cfg.baseUrl || 'https://developers.cjdropshipping.com/api2.0/v1').replace(/\/$/, ''); const res = await axios.post(`${baseUrl}/authentication/getAccessToken`, { apiKey: cfg.apiKey }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000, }); if (!res.data?.result) throw new Error(`CJ token refresh failed: ${JSON.stringify(res.data).slice(0, 200)}`); const token = res.data.data.accessToken; cfg.accessToken = token; cfg.tokenExpiry = now + 14 * 24 * 3600 * 1000; fs.writeFileSync(CJ_API_PATH, JSON.stringify(cfg, null, 2)); console.log(' ✅ CJ token refreshed'); return token; } function cjBaseUrl() { return (cjCfg().baseUrl || 'https://developers.cjdropshipping.com/api2.0/v1').replace(/\/$/, ''); } async function cjHeaders() { return { 'CJ-Access-Token': await cjEnsureToken(), 'Content-Type': 'application/json' }; } async function createCjOrder(orderData) { const res = await axios.post(`${cjBaseUrl()}/shopping/order/createOrder`, orderData, { headers: await cjHeader ...[truncated 3182 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse every configured endpoint with `new URL()` before use. 2. Require the `https:` protocol for both WooCommerce and CJ endpoints. Permit insecure HTTP only through a clearly named, explicit development-only override. 3. Allowlist the documented CJ API hostname. If alternate CJ endpoints are necessary, require an explicit administrator-controlled allowlist rather than trusting arbitrary configuration. 4. Reject URLs containing embedded usernames or passwords. 5. Validate that the final request destination remains approved when redirects occur, or disable redirects for authenticated requests. 6. Separate endpoint configuration from credential files and protect both with restrictive filesystem permissions. 7. Validate configuration before reading or transmitting credentials and fail closed with a non-sensitive error. 8. Use narrowly scoped WooCommerce API credentials limited to the order and product operations actually required. 9. Add automated tests covering hostile hosts, HTTP URLs, malformed URLs, embedded credentials, and redirects to unapproved origins. ]]>
