T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/generateJWTtoken.py:22
- Finding
- Shared credential file is loaded without variable-level least-privilege controls<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generateJWTtoken.py:22-29` **Vulnerability Type**: Excessive credential access and environment-variable override **Risk Level**: Medium ### Vulnerable Code ```python # 尝试加载 dotenv(标准方式读取 .env 文件) try: import dotenv # 优先加载 ~/.openclaw/.env(OpenClaw 标准配置位置) # 若 OpenClaw 已将 env 注入了当前进程,此调用不会覆盖已存在的变量 dotenv.load_dotenv(os.path.expanduser("~/.openclaw/.env"), override=True) except ImportError: # 未安装 dotenv 时跳过,完全依赖环境继承 pass ``` The same behavior is documented in `SKILL.md:28`. ### Technical Analysis The Skill only needs `QWEATHER_SUB` and `QWEATHER_KID`, but `load_dotenv()` loads every variable found in the shared `~/.openclaw/.env` file into the process environment. This can expose unrelated credentials to the script and all code executing in the same process. The use of `override=True` also replaces existing process-environment values with values from the file. This contradicts the adjacent comment claiming that existing variables will not be overwritten. Consequently, caller-supplied QWeather identifiers or other environment settings may be silently replaced. No code in the audited project sends these values over the network or directly reads unrelated variables. The risk is instead an unnecessary expansion of the credential exposure boundary. Imported packages and future code changes can access all loaded values through `os.environ`, despite the declared operation requiring only two variables. ### Attack Path 1. The user's shared `~/.openclaw/.env` contains QWeather configuration and unrelated service credentials. 2. The user invokes the JWT-generation Skill. 3. The script loads every entry from that file into `os.environ`, using file values to override inherited values. 4. A compromised or substituted dependency executing later in the process—such as code reached through `jwt.encode()`—enumerates `os.environ`. 5. The dependency obtains unrelated credentials that wer ...[truncated 1032 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not inject the entire shared credential file into `os.environ`. 2. Parse the file without globally mutating the process environment, then select only the required variables: ```python from dotenv import dotenv_values config = dotenv_values(os.path.expanduser("~/.openclaw/.env")) sub = os.environ.get("QWEATHER_SUB") or config.get("QWEATHER_SUB") kid = os.environ.get("QWEATHER_KID") or config.get("QWEATHER_KID") ``` 3. Apply an explicit allowlist containing only `QWEATHER_SUB` and `QWEATHER_KID`. 4. Prefer inherited environment variables over file values so that explicit caller configuration is not unexpectedly replaced. 5. If `load_dotenv()` must remain, use `override=False`; however, this still loads unrelated entries and is less secure than allowlisted parsing. 6. Correct the documentation and comments so that the stated precedence matches the implementation. 7. Consider storing QWeather credentials in a dedicated configuration file with mode `0600`, rather than a shared file containing credentials for multiple services. ]]>
