T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/codex-cli-sync.py:55
- Finding
- Plaintext OAuth credential backups may be created with unsafe permissions## Vulnerability Details **File Location**: `scripts/codex-cli-sync.py`, lines 55–59 **Vulnerability Type**: Insecure storage of sensitive credentials **Risk Level**: Medium ### Vulnerable Code ```python def backup_file(path: Path) -> Path | None: if not path.exists(): return None backup = path.with_name(f"{path.name}.bak-{time.strftime('%Y%m%d-%H%M%S')}") backup.write_bytes(path.read_bytes()) return backup ``` The function is called before the token-bearing OpenClaw profile store is updated: ```python prof_backup = backup_file(PROFILES_PATH) state_backup = backup_file(STATE_PATH) if not args.no_set_first else None store["profiles"][profile_id] = credential atomic_write_json(PROFILES_PATH, store) ``` ### Technical Analysis `auth-profiles.json` contains OAuth access and refresh tokens. Before modifying that file, `backup_file()` creates a complete plaintext copy under a timestamped `.bak-*` filename. The backup is created through `Path.write_bytes()` without explicitly setting owner-only permissions. Its effective permissions therefore depend on the process umask and parent-directory access controls. Under a permissive environment, another local user or process may be able to read the backup. These backups also have no retention or cleanup mechanism. Consequently, expired and potentially still-valid refresh tokens can remain on disk after the active credential store has changed. This increases both the number of credential copies and the duration of exposure. ### Attack Path 1. A legitimate user runs `python3 scripts/codex-cli-sync.py`. 2. The script reads the existing OpenClaw profile store containing OAuth credentials. 3. `backup_file()` writes the entire store to a timestamped plaintext backup. 4. The backup receives permissions based on the runtime umask rather than an explicit `0600` policy. 5. If the file and parent directories are accessible, another local principa ...[truncated 919 chars]
- Remediation
- ## Remediation Suggestions - Create backup files atomically with explicit owner-only permissions, such as `os.open()` with `O_CREAT | O_EXCL | O_WRONLY` and mode `0o600`. - Apply `os.chmod(backup, 0o600)` after creation as defense in depth, while avoiding any interval in which the file is broadly readable. - Verify that the OpenClaw credential directory is owner-controlled and not writable or traversable by unrelated users. - Preserve restrictive permissions when replacing the primary credential store; explicitly enforce `0600` on token-bearing files. - Implement bounded backup retention and promptly remove obsolete credential backups. - Warn users that backups contain complete plaintext credentials. - Revoke affected OAuth sessions and delete exposed backups if permissive backups may already have been created. - Consider encrypting backups with a user-controlled key or omitting automatic credential backups unless the user explicitly requests them.
