T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/questrade_cli.py:154
- Finding
- OAuth token files are written without explicitly restrictive permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/questrade_cli.py:154-155` and `scripts/questrade_cli.py:205-209` **Vulnerability Type**: Insecure storage of sensitive authentication tokens **Risk Level**: Medium ### Vulnerable Code ```python with open(CREDENTIALS_FILE, "w") as f: json.dump(config, f, indent=2) ``` ```python with open(TOKEN_CACHE_FILE, "w") as f: json.dump( {"access_token": access_token, "api_server": api_server, "expires_at": expires_at.isoformat()}, f, indent=2, ) ``` ### Technical Analysis The application persists both a rotating OAuth refresh token and a bearer access token using the default permissions derived from the process umask. It does not explicitly create these files with mode `0600`, restrict the parent directories to `0700`, or correct the permissions of existing files. On a system with a permissive umask or previously created broadly accessible files, another local account may be able to read the tokens. The files also are not updated atomically, which can leave partially written credential state if the process is interrupted. The refresh token has greater security significance because it can be exchanged for new access tokens. The access-token cache additionally stores the API server to which the bearer token will subsequently be sent. ### Attack Path 1. A user executes the Questrade CLI on a multi-user host under a permissive umask. 2. The CLI refreshes its OAuth credentials. 3. The rotated refresh token is written to `~/.openclaw/credentials/questrade.json`, and the bearer access token is written to `~/.openclaw/data/questrade-token-cache.json`. 4. The resulting permissions allow another local user or compromised process to read one or both files. 5. The attacker exchanges the refresh token or directly uses the cached bearer token against the Questrade API. 6. The attacker accesses the API resources authorized by the token. ### Impact Assessment A stolen personal to ...[truncated 492 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Create credential and cache directories with mode `0700`. - Create token files atomically with mode `0600`, for example by using `os.open()` with `O_CREAT | O_WRONLY` and an explicit mode. - Apply `chmod(0o600)` to existing token files before reading or updating them. - Write updates to a securely created temporary file in the same directory, flush and synchronize it, and atomically replace the destination. - Reject symbolic links and verify that credential files are regular files owned by the current user. - Avoid copying the rotated refresh token into `os.environ`, because environment values may be exposed to debugging or process-inspection mechanisms. - Document the required local permissions and provide a migration step that repairs existing installations. ]]>
