T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/send_agreement.py:216
- Finding
- Unvalidated Service Endpoints Can Expose Agreements and Bearer Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/send_agreement.py`, lines 216–221, 235–246, and 259–264 **Vulnerability Type**: Arbitrary network destination and insecure transport configuration **Risk Level**: High ### Vulnerable Code ```python nanopdf_base = read_env("NANOPDF_BASE_URL") nanopdf_key = read_env("NANOPDF_API_KEY") nanopdf_detect_path = read_env( "NANOPDF_DETECT_PATH", required=False, default="/v1/signature-blocks", ) docusign_base = read_env("DOCUSIGN_BASE_URL") docusign_account_id = read_env("DOCUSIGN_ACCOUNT_ID") docusign_token = read_env("DOCUSIGN_ACCESS_TOKEN") ``` ```python detect_url = f"{nanopdf_base.rstrip('/')}/{nanopdf_detect_path.lstrip('/')}" nanopdf_payload = { "document_name": pdf_path.name, "document_base64": pdf_b64, "labels": ["signature"], } nanopdf_response = http_json( url=detect_url, method="POST", payload=nanopdf_payload, headers={"Authorization": f"Bearer {nanopdf_key}"}, ) ``` ```python envelope_url = ( f"{docusign_base.rstrip('/')}/restapi/v2.1/" f"accounts/{docusign_account_id}/envelopes" ) envelope_result = http_json( url=envelope_url, method="POST", payload=docusign_payload, headers={"Authorization": f"Bearer {docusign_token}"}, ) ``` ### Technical Analysis The Skill must transmit agreement data to NanoPDF and DocuSign to perform its declared function. Base64 encoding of the PDF is part of those documented API request formats and is not, by itself, evidence of covert exfiltration. However, the destinations are taken directly from environment variables without enforcing HTTPS or validating the destination hostname. The generic `urlopen` request path will therefore send the PDF and corresponding bearer credential to any syntactically accepted URL supplied through the environment. This exceeds safe least-privilege network behavior because the Skill needs access only to the intended NanoPDF and DocuSign services, not arbitrary network d ...[truncated 1807 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require `https` for both configured service URLs and reject plaintext HTTP. 2. Parse URLs with `urllib.parse.urlsplit` rather than relying on string concatenation. 3. Maintain explicit hostname allowlists for approved NanoPDF and DocuSign environments. 4. Reject URLs containing user information, unexpected ports, fragments, or malformed hostnames. 5. Reject loopback, link-local, private, and metadata-service destinations unless an explicitly approved private deployment requires them. 6. Disable automatic redirects or validate every redirect target against the same scheme and hostname policy. 7. Keep separate credentials for each service and never forward one service's credential across origin boundaries. 8. Validate `DOCUSIGN_ACCOUNT_ID` as an expected identifier before inserting it into the request path. 9. Use narrowly scoped and short-lived access tokens. 10. Log only the normalized destination hostname, never authorization headers or complete request bodies. ]]>
