T09 · Insecure Skill Coding Practices
- Location
scripts/config.py:43- Finding
API Key Persisted in an Unprotected Plaintext File
- Content
View full analysis
Vulnerability Details
File Location:
scripts/config.py:43-61
Vulnerability Type: Plaintext credential storage with insufficient file protection
Risk Level: MediumVulnerable Code
python def save_api_key_to_env(api_key: str) -> bool: """将API key保存到.env文件""" try: env_path = Path(".env") lines = [] if env_path.exists(): lines = env_path.read_text(encoding="utf-8").splitlines() found = False new_lines = [] for line in lines: if line.startswith("XBY_APIKEY="): new_lines.append(f"XBY_APIKEY={api_key}") found = True else: new_lines.append(line) if not found: new_lines.append(f"XBY_APIKEY={api_key}") env_path.write_text("\n".join(new_lines) + "\n", encoding="utf-8") os.environ["XBY_APIKEY"] = api_key return TrueTechnical Analysis
The function writes the user-supplied API key in plaintext to a predictable
.envfile in the process's current working directory.Path.write_text()does not explicitly enforce restrictive permissions such as0600; effective permissions depend on the operating system and process umask.The code also does not verify that
.envis a regular file owned by the current user. If an attacker can control the working directory or pre-create.envas a symbolic link, the write may follow that link. The read-modify-write operation is not atomic, creating an additional opportunity for race conditions.The credential is also copied into the process environment, where it may be exposed to same-user diagnostic tools, crash reporting, or child processes.
Attack Path
- A user supplies a valid API key as required by the Skill workflow.
- The Agent calls
set_api_key(), which invokessave_api_key_to_env(). - The API key is written as `XBY_APIKEY=<secret> ...[truncated 1223 chars]
- Remediation
View remediation
Remediation Suggestions
- Prefer a platform credential manager, operating-system keyring, or session-only secret injection instead of plaintext file persistence.
- If file storage is required, use a fixed per-user configuration directory rather than the current working directory.
- Create the credential file with restrictive
0600permissions and verify permissions after every replacement. - Reject symbolic links and verify that the destination is a regular file owned by the current user.
- Write to a securely created temporary file in the same directory, set its permissions, flush it, and atomically replace the destination.
- Add
.envto.gitignoreand provide automated secret scanning in continuous integration. - Avoid copying the key into the process environment unless required. Never pass it to child processes.
- Document the storage location and obtain explicit user consent before persisting the credential.
