T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/prana_skill_client.py:218
- Finding
- Caller-Controlled API Endpoint Can Receive Credentials, Identity Data, and User Messages<![CDATA[ ## Vulnerability Details **File Location**: `scripts/prana_skill_client.py:218-264`, `scripts/prana_skill_client.py:455-480`, and `scripts/prana_skill_client.py:502` **Vulnerability Type**: Unrestricted transmission of sensitive information to a configurable network endpoint **Risk Level**: High ### Complete Code Snippet ```python def _build_api_keys_fetch_url(base_url: str) -> str: """ 组装 GET /api/v1/api-keys 完整 URL。 查询参数(与 Prana 服务端一致):account_id、email、phone_number;均可从环境变量注入。 若全无则服务端会为随机新用户签发 key(见 api_keys_api.get_api_keys)。 """ root = base_url.rstrip("/") path = f"{root}/api/v1/api-keys" q: Dict[str, str] = {} aid = (os.environ.get("ACCOUNT_ID") or os.environ.get("PRANA_ACCOUNT_ID") or "").strip() if aid: q["account_id"] = aid email = (os.environ.get("PRANA_API_KEYS_EMAIL") or os.environ.get("EMAIL") or "").strip() if email: q["email"] = email phone = ( os.environ.get("PHONE_NUMBER") or os.environ.get("PRANA_PHONE") or os.environ.get("phone_number") or "" ).strip() if phone: q["phone_number"] = phone if q: path = f"{path}?{urlencode(q)}" return path def fetch_prana_api_keys_via_get(base_url: str) -> Optional[Tuple[str, str]]: """ 调用 Prana GET /api/v1/api-keys(无需 JWT),解析 data.api_key 的 public_key、secret_key。 """ url = _build_api_keys_fetch_url(base_url) req = urllib.request.Request(url, method="GET") try: with urllib.request.urlopen(req, timeout=API_KEYS_FETCH_TIMEOUT_SEC) as resp: text = resp.read().decode("utf-8") ``` ```python def invoke_prana( base_url: str, skill_key: str, content: str, thread_id: str | None, request_id: str, public_key: str, secret_key: str, ) -> dict: """ 调用 Prana 技能执行接口。 body: skill_key, question, thread_id, request_id(不含 api_key) Header: x-api-key: public_key:secret_key 若 HTTP 超时、连接失败,或网关类错误(5xx / ...[truncated 4284 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Enforce HTTPS for all non-mock network requests and reject URLs using `http://`, unsupported schemes, embedded credentials, or malformed hosts. 2. Pin the production endpoint to the expected Prana hostname or implement a narrow, explicit allowlist of trusted Prana hosts. 3. Disable arbitrary `--base-url` and `NEXT_PUBLIC_URL` overrides in production builds. If overrides are needed for development, require an explicit development mode and display the destination before sending secrets. 4. Remove fallback reads from generic variables such as `EMAIL`, `PHONE_NUMBER`, `phone_number`, and `ACCOUNT_ID`. 5. Only use explicitly scoped names such as `PRANA_ACCOUNT_ID`, `PRANA_API_KEYS_EMAIL`, and `PRANA_PHONE`. 6. Require explicit user consent before transmitting identity attributes during automatic credential creation. 7. Consider disabling automatic key acquisition by default. Require the user to opt in or configure credentials through a trusted provisioning workflow. 8. Validate redirects or disable cross-origin redirects so a trusted initial endpoint cannot redirect credential-bearing traffic to another host. 9. Separate credential acquisition and authenticated API destinations, validating both against the trusted-host policy. 10. Clearly notify users that their full message is sent to a remote service and advise them not to include unnecessary secrets. ]]>
