T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/news_digest_v2/stage2_5_llm_summary.py:26- Finding
Silent Access and Use of an Unrelated OpenClaw API Credential
- Content
View full analysis
Vulnerability Details
File Location:
scripts/news_digest_v2/stage2_5_llm_summary.py, lines 26–75
Vulnerability Type: Unauthorized credential access and use
Risk Level: HighVulnerable Code
python # LLM Configuration (use environment variables, fallback to OpenClaw config) API_KEY = os.environ.get('NEWS_DIGEST_LLM_API_KEY', '') BASE_URL = os.environ.get('NEWS_DIGEST_LLM_BASE_URL', '') MODEL = os.environ.get('NEWS_DIGEST_LLM_MODEL', 'qwen3.6-plus') def load_llm_config(): """Fallback: try to load from OpenClaw config if env vars not set""" global API_KEY, BASE_URL if API_KEY and BASE_URL: return True try: config_path = os.path.expanduser(r"~\.openclaw\openclaw.json") with open(config_path, 'r', encoding='utf-8-sig') as f: config = json.load(f) provider = config['models']['providers']['custom-coding-dashscope-aliyuncs-com'] API_KEY = provider['apiKey'] BASE_URL = provider['baseUrl'] return True except Exception as e: print(f" ⚠️ LLM config load failed: {e}") return False def call_llm(prompt, max_tokens=4000, temperature=0.3): """Call LLM API""" if not API_KEY or not BASE_URL: load_llm_config() if not API_KEY or not BASE_URL: print(f" ⚠️ LLM not configured, skipping summary") return None if not API_KEY: return None req_data = json.dumps({ 'model': MODEL, 'messages': [{'role': 'user', 'content': prompt}], 'temperature': temperature, 'max_tokens': max_tokens }).encode('utf-8') req = urllib.request.Request( f'{BASE_URL}/chat/completions', data=req_data, headers={ 'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json' } ) try: with urllib.request.urlopen(req, ...[truncated 2609 chars]- Remediation
View remediation
Remediation Suggestions
- Remove the OpenClaw configuration fallback entirely.
- Require explicit
NEWS_DIGEST_LLM_API_KEYandNEWS_DIGEST_LLM_BASE_URLvalues dedicated to this Skill. - Keep LLM processing disabled unless the user explicitly opts in.
- Update the full workflow so Stage 2.5 is called only when explicit LLM configuration and consent are present.
- Validate the LLM endpoint:
- Require HTTPS.
- Permit only expected hostnames and ports.
- Reject embedded credentials, fragments, loopback addresses, private addresses, link-local addresses, and redirects to unapproved hosts.
- Clearly disclose that article titles, sources, and up to 800 characters of article content per item are transmitted.
- Use a narrowly scoped API key with usage limits and separate billing controls.
- Never print credentials or include authorization headers in exception details.
