T09 · Insecure Skill Coding Practices
- Location
scripts/search.py:48- Finding
Unrelated Provider Credential May Be Disclosed to Zhipu
- Content
View full analysis
Vulnerability Details
File Location:
scripts/search.py, lines 48–60 and 69–73
Vulnerability Type: Credential selection and unintended disclosure
Risk Level: MediumVulnerable Code
python def _zhipu_key(): key = os.environ.get("ZHIPU_API_KEY") if key: return key config_path = os.path.expanduser("~/.openclaw/openclaw.json") if os.path.exists(config_path): try: with open(config_path) as f: cfg = json.load(f) for p in ["generic", "glm"]: k = cfg.get("models", {}).get("providers", {}).get(p, {}).get("apiKey", "") if k: return k except Exception: pass return ""The returned value is subsequently placed in the authorization header:
python headers = { "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", "Accept": "application/json, text/event-stream", }Requests carrying that header are sent to the fixed Zhipu endpoint:
python req = urllib.request.Request( ZHIPU_MCP_URL, data=init_payload, headers=headers, method="POST", )Technical Analysis
The
_zhipu_key()function treatsmodels.providers.generic.apiKeyas a Zhipu credential without checking which service the generic provider represents. Becausegenericis checked beforeglm, any nonempty generic provider key is selected even when a valid Zhipu-specificglmkey is available.The selected value is used as a bearer credential in HTTPS requests to
https://open.bigmodel.cn/api/mcp/web_search_prime/mcp. If the generic key belongs to another service, the Skill discloses an unrelated credential to Zhipu. Reading and transmitting arbitrary provider credentials exceeds the minimum privilege required for the declared web-search fallback.The use of HTTPS protects the credential in transit from ordinary passive interception, but it does not prevent disclosure to the d ...[truncated 1326 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove
genericfrom automatic Zhipu credential discovery and accept only an explicitly scoped credential:
python def _zhipu_key(): key = os.environ.get("ZHIPU_API_KEY") if key: return key config_path = os.path.expanduser("~/.openclaw/openclaw.json") try: with open(config_path, encoding="utf-8") as f: cfg = json.load(f) return ( cfg.get("models", {}) .get("providers", {}) .get("glm", {}) .get("apiKey", "") ) except (OSError, ValueError, TypeError): return ""- Prefer requiring
ZHIPU_API_KEYexplicitly rather than inferring credentials from broadly named provider entries. - If provider-based discovery must remain, verify that the provider identifier and configured base URL match a strict allowlist of approved Zhipu endpoints before using its key.
- Never send a credential selected from one provider configuration to another provider's endpoint.
- Document the exact credential lookup behavior in
SKILL.mdso users understand which local configuration fields may be read. - Add tests confirming that:
generic.apiKeyis never returned as a Zhipu key.glm.apiKeyis selected only for Zhipu.- An explicit
ZHIPU_API_KEYtakes precedence. - Absence of a correctly scoped key fails closed without making an authenticated request.
- Remove
