T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/resolve_key.py:29
- Finding
- Overbroad Loading of Unrelated Secrets from Environment Files<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/resolve_key.py:29-38` - `scripts/discover_models.py:34-39` - `scripts/proxy_query.py:64-73` - `references/typescript_template.md:57-67` **Vulnerability Type**: Excessive credential access and violation of least privilege **Risk Level**: Medium ### Vulnerable Code ```python # scripts/resolve_key.py:29-38 # 1. Global ~/.env env.update(load_dotenv_simple(Path.home() / ".env")) # 2. Project .env (overrides global) env.update(load_dotenv_simple(Path(".env"))) # 3. Shell environment (highest priority) env.update(os.environ) key = env.get("OPENROUTER_API_KEY", "").strip() ``` Equivalent behavior exists in the other affected implementations: ```python # scripts/proxy_query.py:64-73 def get_env() -> dict: env = {} env.update(load_env_file(Path.home() / ".env")) env.update(load_env_file(Path(".env"))) env.update(os.environ) return env def get_key(env: dict) -> str: key = env.get("OPENROUTER_API_KEY", "").strip() ``` ```typescript // references/typescript_template.md:57-67 function resolveEnv(): Record<string, string> { // 1. Project .env 2. ~/.env 3. process.env (already exported) const projectEnv = loadEnvFile(path.join(process.cwd(), ".env")); const globalEnv = loadEnvFile(path.join(os.homedir(), ".env")); // Later entries win — process.env takes precedence return { ...globalEnv, ...projectEnv, ...process.env as Record<string, string> }; } const ENV = resolveEnv(); function getApiKey(): string { const key = ENV["OPENROUTER_API_KEY"]?.trim(); ``` ### Technical Analysis The Skill requires only a limited set of OpenRouter-related values, principally `OPENROUTER_API_KEY`, `OPENROUTER_PREFERRED_MODELS`, `OPENROUTER_TIER_A`, and `OPENROUTER_TIER_B`. Instead, the implementations parse every entry in the project `.env`, the global `~/.env`, and the complete process environment into Skill-controlled dictionaries. Global `.env` files commonly contain unrelated da ...[truncated 1370 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Retrieve only explicitly approved keys instead of constructing a dictionary containing every environment entry. - Prefer the process environment and a project-specific configuration file. - Do not inspect global `~/.env` by default. If global configuration is required, use a dedicated file such as `~/.config/openrouter-connect/config.env`. - Apply restrictive permissions to dedicated configuration files, such as mode `0600`. - Replace broad parsing with an allowlist: ```python ALLOWED_KEYS = { "OPENROUTER_API_KEY", "OPENROUTER_PREFERRED_MODELS", "OPENROUTER_TIER_A", "OPENROUTER_TIER_B", } def load_allowed_env(path: Path) -> dict[str, str]: values = load_env_file(path) return {key: values[key] for key in ALLOWED_KEYS if key in values} ``` - Avoid retaining the API key longer than necessary and never include it in logs, exceptions, or diagnostic state. ]]>
