T09 · Insecure Skill Coding Practices
- Location
scripts/common.py:91- Finding
Plaintext API credential file is created without restrictive permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/common.py:91-96
Vulnerability Type: Insecure storage of bearer credentials
Risk Level: MediumVulnerable Code
python def save_memory_config(memory_config: dict[str, Any], memory_file: str | Path | None = None) -> Path: path = resolve_memory_file(str(memory_file) if memory_file is not None else None) path.parent.mkdir(parents=True, exist_ok=True) try: path.write_text(json.dumps(memory_config, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") except OSError as exc: raise ConfigError(f"Failed to write memory file {path}: {exc}") from exc return pathThe credential is added to this configuration before it is saved:
python if getattr(args, "save_to_memory", False): updated_config = dict(memory_config) updated_config["base_url"] = base_url updated_config["api_key"] = api_key save_memory_config(updated_config, memory_file) memory_config = updated_configTechnical Analysis
The documented
--save-to-memoryworkflow stores the RAGFlow bearer API key in plaintext. The code usesPath.write_text()without explicitly creating the file with owner-only permissions or subsequently enforcing a mode such as0600.Consequently, the effective permissions depend on the process umask and the permissions of any pre-existing user-selected memory file. In an environment with a permissive umask or unsafe existing file permissions, other local users or processes may be able to read the bearer token.
The default location under
~/.codex/memories/reduces accidental exposure but does not guarantee that the file itself is owner-only. The--memory-fileoption can also select another location with weaker directory protections.Attack Path
- The user invokes a documented command with
--save-to-memory. resolve_runtime_config()adds the resolved bearer token to the ...[truncated 938 chars]
- The user invokes a documented command with
- Remediation
View remediation
Remediation Suggestions
- Create new credential files atomically with owner-only permissions, for example by using
os.open()withO_CREAT | O_EXCLand mode0o600. - Enforce
0600after writing and verify that the resulting file is owned by the current user. - Reject symbolic links and existing files with group or world permissions before storing credentials.
- Create the parent credential directory with mode
0700. - Write through a securely created temporary file in the same directory, then atomically replace the destination.
- Prefer an operating-system credential manager or keyring instead of plaintext JSON where available.
- Clearly warn users that
--save-to-memorypersists the bearer token and provide a command to remove the stored credential.
- Create new credential files atomically with owner-only permissions, for example by using
