T09 · Insecure Skill Coding Practices
- Location
swanlab_reader.py:61- Finding
SwanLab API Key Exposed Through Process Arguments and Insecure Plaintext Storage
- Content
View full analysis
Vulnerability Details
File Location:
swanlab_reader.py:61-64,swanlab_reader.py:352-357, andSKILL.md:17-20
Vulnerability Type: API credential exposure through command-line arguments and insufficient file permission enforcement
Risk Level: MediumVulnerable Code
python def save_api_key(key): os.makedirs(CONFIG_DIR, exist_ok=True) with open(CONFIG_KEY_FILE, "w") as f: f.write(key)python if action == "set-key": if len(sys.argv) < 3: print("用法: swanlab set-key <key>") sys.exit(1) save_api_key(sys.argv[2]) print("Key 已保存到 ~/.config/swanlab/key") sys.exit(0)The documented invocation also instructs users to place the secret directly in a command-line argument:
bash uv run python skills/swanlab-reader/swanlab_reader.py set-key <your-key>Technical Analysis
The
set-keycommand obtains the SwanLab API key fromsys.argv[2]. Command-line arguments may be recorded in shell history and can be exposed through process-inspection facilities while the command is running. This unnecessarily expands the number of local components that may observe the credential.The key is subsequently written in plaintext to
~/.config/swanlab/key. Plaintext storage is consistent with the declared credential mechanism, but the implementation does not explicitly enforce owner-only permissions. Both the configuration directory and key file inherit permissions from the process umask. Under an insufficiently restrictive umask, other local accounts or processes may be able to read the key.The code does not contain evidence of deliberate credential exfiltration. Network requests attach the key as a Bearer token only to the fixed HTTPS origin
https://swanlab.cn, which is necessary for the Skill's declared private-project access. The vulnerability instead arises from avoidable local exposure before the key is used.Attack Path
- A user follows the documented command ...[truncated 1402 chars]
- Remediation
View remediation
Remediation Suggestions
-
Remove secrets from command-line arguments
- Prompt interactively with
getpass.getpass()so the key is not echoed or placed in process arguments. - Alternatively, accept the key through protected standard input or a dedicated secret manager.
- Retain environment-variable support only where users understand that environment values may be visible to child processes or diagnostic tooling.
- Prompt interactively with
-
Enforce owner-only filesystem permissions
- Create
~/.config/swanlabwith mode0700. - Create the key file atomically with mode
0600, rather than relying on the user's umask. - Verify and correct permissions on existing directories and key files before reading them.
- Reject symbolic-link targets or use safe open flags to prevent writing through an attacker-controlled link.
- Create
-
Use atomic credential writes
- Write to an owner-only temporary file in the same directory, flush it, and atomically replace the destination.
- Ensure failures cannot leave a partially written or unexpectedly permissioned credential file.
-
Update the documentation
- Replace
set-key <your-key>with an interactiveset-keyworkflow. - Warn users not to place API keys in shell history, scripts, logs, or copied terminal output.
- Recommend revoking and rotating any key suspected of exposure.
- Replace
A hardened interface could use
set-keywithout a secret argument, collect the key throughgetpass.getpass("SwanLab API key: "), create the configuration directory with0700, and save the credential to an atomically created0600file.-
