T09 · Insecure Skill Coding Practices
- Location
SKILL.md:23- Finding
API Key Persisted in an Unprotected Plaintext Configuration File
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 23-37
Vulnerability Type: Plaintext credential storage and unsafe secret persistence
Risk Level: MediumVulnerable Code Snippet
markdown ## Credentials - Required: `APICLAW_API_KEY` - Scope: used only for `https://api.apiclaw.io` - Resolution order: 1. **Environment variable** `APICLAW_API_KEY` (preferred, most secure) 2. **Config file** `config.json` in the skill root directory (fallback) ```json { "api_key": "hms_live_xxxxxx" }When user provides a Key, write it to
config.json. New keys may need 3-5 seconds to activate — if first call returns 403, wait 3 seconds and retry (max 2 retries).⚠️ Data persistence notice: When you provide an API Key, the skill saves it to
config.jsonin the skill directory for persistent access across sessions. This file is local-only and listed in.gitignoreto prevent accidental commits.text The corresponding credential-loading implementation is located in `scripts/apiclaw.py`, lines 70-86: ```python key = os.environ.get("APICLAW_API_KEY", "").strip() if key: return key script_dir = os.path.dirname(os.path.abspath(__file__)) skill_dir = os.path.dirname(script_dir) config_path = os.path.join(skill_dir, "config.json") if os.path.exists(config_path): try: with open(config_path, "r", encoding="utf-8") as f: config = json.load(f) key = config.get("api_key", "").strip() if key: return key except (json.JSONDecodeError, IOError) as e: print(f"WARNING: Failed to read config file: {e}", file=sys.stderr)Technical Analysis
The Skill explicitly directs the agent to write user-provided API keys into
config.jsonin plaintext. No file-permission requirement, encryption, operating-system credential-store integration, or automatic deletion mechanism is specifie ...[truncated 2584 chars]- Remediation
View remediation
Remediation Suggestions
-
Remove the instruction that automatically writes user-provided credentials into the Skill directory.
-
Use
APICLAW_API_KEYas the default and preferred credential source without creating a file. -
If persistent storage is essential, use an operating-system credential store or a platform-provided secret manager.
-
If file-based storage must remain:
- require explicit informed user consent before persistence;
- store the file outside the project or repository tree;
- create it atomically with owner-only permissions, such as mode
0600on POSIX systems; - reject files owned by another user or files with unsafe permissions;
- document rotation and deletion procedures;
- avoid displaying the key in commands, logs, exceptions, or generated output.
-
Include an actual
.gitignorecontaining at least:gitignore config.json *.key .envThis should be treated only as defense in depth, not as the primary secret-protection mechanism.
-
Add secret scanning to CI and release workflows to detect
hms_live_tokens and other credential patterns. -
Provide a command to delete stored credentials and advise users to rotate any key that may have entered version control or backups.
-
