T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/invoice_service.js:84
- Finding
- Sensitive invoice data and bearer credentials are transmitted over configurable plaintext HTTP endpoints<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:26-32`, `README.md:26-32`, `scripts/invoice_service.js:84-108`, `scripts/invoice_service.js:536-548`, `scripts/invoice_service.js:650-660` **Vulnerability Type**: Plaintext transmission of sensitive data and insufficient destination validation **Risk Level**: High ### Evidence The mandatory first-time setup directs users to configure a remote service over plaintext HTTP: ```markdown If the user has not configured the API base URL yet, run: ```bash node "{baseDir}/scripts/invoice_service.js" config set --api-base-url http://asset-check-innovate-service-http.default.yf-bw-test-2.test.51baiwang.com ``` ``` The README provides another plaintext HTTP configuration example: ```bash node "{baseDir}/scripts/invoice_service.js" config set --api-base-url http://192.168.154.76:18888 ``` The application sends its bearer credential to the configured URL without requiring HTTPS or validating the destination: ```javascript function buildHeaders(appKey, requestId) { const headers = { "Content-Type": "application/json" }; if (requestId) { headers["X-Request-Id"] = requestId; } if (appKey) { headers.Authorization = `Bearer ${appKey}`; } return headers; } async function callApi(baseUrl, method, endpoint, body, appKey, requestId) { let response; try { response = await fetch(`${baseUrl}${endpoint}`, { method, headers: buildHeaders(appKey, requestId), body: body ? JSON.stringify(body) : undefined }); ``` Local invoice images are read in full and converted to Base64: ```javascript if (options["image-file"]) { const filePath = path.resolve(String(options["image-file"])); if (!fs.existsSync(filePath)) { throw new Error(`image file not found: ${filePath}`); } const mimeType = options["mime-type"] || getMimeTypeFromPath(filePath); const buffer = fs.readFileSync(filePath); return { imageSource: "file", imagePath: filePath, mimeType, ...[truncated 3060 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require HTTPS for every non-loopback API destination: - Parse the URL with the standard `URL` class. - Reject `http:` unless the host is explicitly limited to `localhost`, `127.0.0.1`, or another narrowly defined development exception. - Do not publish a production or test setup command using HTTP. 2. Restrict destinations: - Maintain an explicit allowlist of trusted production API hostnames. - Reject URLs containing embedded credentials, unexpected ports, fragments, or unsupported schemes. - Consider requiring explicit confirmation before accepting a non-default host. 3. Protect server authenticity: - Use valid TLS certificates. - Do not disable certificate verification. - Consider certificate or public-key pinning if the production backend is fixed and operationally supports rotation. 4. Minimize transmitted data: - Send only fields required by the selected verification method. - Avoid transmitting both complete invoice content and redundant extracted fields unless the API requires both. - Clearly disclose that local images and same-name sidecar text files will be uploaded. 5. Add user confirmation before file upload: - Display the resolved destination host and files selected for transmission. - Require explicit approval for batch directory uploads, particularly recursive uploads. 6. Rotate any app keys previously used over plaintext HTTP and treat previously submitted invoice data as potentially exposed. ]]>
