T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/index.js:90
- Finding
- Unvalidated Appian Base URL Can Expose API Credentials and Uploaded Package Data## Vulnerability Details **File Location**: `scripts/index.js`, lines 34 and 90–94 **Vulnerability Type**: Unvalidated sensitive-data destination and plaintext transport **Risk Level**: Medium ### Vulnerable Code ```javascript const baseUrl = process.env.APPIAN_BASE_URL?.replace(/\/$/, ''); ``` ```javascript async function sendInspection(credentials, formData) { const res = await fetch(`${credentials.baseUrl}/inspections`, { method: 'POST', headers: { 'appian-api-key': credentials.apiKey }, body: formData, }); ``` ### Technical Analysis `APPIAN_BASE_URL` is accepted directly from the environment or from a discovered `appian.json` configuration file. The value is only normalized by removing one trailing slash. The implementation does not parse and validate the URL, require HTTPS, reject embedded credentials or unusual ports, or constrain the destination to an approved Appian host. The unvalidated value is subsequently used as the destination for an authenticated request containing: - The Appian API key in the `appian-api-key` header. - The user-selected Appian package ZIP. - The optional customization file. - Package and customization filenames. If the URL uses plaintext HTTP, these values may be intercepted or modified by a network-positioned attacker. If an attacker can influence the environment or configuration lookup, the attacker can direct the request to a server they control and receive both the credential and uploaded files. The exposure risk is increased by the configuration lookup behavior at lines 27–33: when credentials are absent from the environment, the program searches the current directory and up to four ancestor directories for `appian.json`. This may cause it to trust configuration outside the intended project directory. ### Attack Path 1. The victim runs the skill without a trusted `APPIAN_BASE_URL` already present in the environment. 2. An att ...[truncated 1617 chars]
- Remediation
- ## Remediation Suggestions 1. Parse the configured endpoint with the standard URL parser and reject malformed values. 2. Require the `https:` protocol before transmitting credentials or package data. 3. Reject URLs containing embedded usernames or passwords. 4. Restrict ports to approved TLS ports unless a documented deployment requirement exists. 5. Where the expected Appian domains are known, enforce an exact hostname or suffix allowlist. Avoid substring-based hostname checks. 6. Restrict fallback configuration loading to an explicit path or the current working directory. Do not silently search ancestor directories. 7. Fail closed when endpoint validation fails, before reading package files or initiating network requests. 8. Document the accepted endpoint format and trusted-host policy. 9. Add tests covering plaintext HTTP URLs, malformed URLs, embedded credentials, deceptive hostnames, unexpected ports, and untrusted ancestor configuration files. Example validation pattern: ```javascript function validateBaseUrl(rawBaseUrl) { let url; try { url = new URL(rawBaseUrl); } catch { throw new Error('APPIAN_BASE_URL must be a valid URL'); } if (url.protocol !== 'https:') { throw new Error('APPIAN_BASE_URL must use HTTPS'); } if (url.username || url.password) { throw new Error('APPIAN_BASE_URL must not contain credentials'); } if (url.search || url.hash) { throw new Error('APPIAN_BASE_URL must not contain a query or fragment'); } // Apply an exact organization-approved hostname policy here. // Example: if (!APPROVED_HOSTS.has(url.hostname)) throw new Error(...); return url.href.replace(/\/$/, ''); } ``` Credentials exposed through a potentially unsafe configuration should be revoked and rotated after the endpoint configuration is corrected.
