T09 · Insecure Skill Coding Practices
- Location
scripts/checkup.py:27- Finding
Anthropic API Key Stored Without Enforced Restrictive Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/checkup.py, lines 27-42;references/deep-analysis-setup.md, lines 31-39
Vulnerability Type: Plaintext credential storage with insecure default permissions
Risk Level: MediumVulnerable Code
python def ensure_dirs(): CONFIG_DIR.mkdir(parents=True, exist_ok=True) STATE_DIR.mkdir(parents=True, exist_ok=True) if not CONFIG_FILE.exists(): CONFIG_FILE.write_text(json.dumps( {"slugs": [], "plugins": [], "anthropic_api_key": None}, indent=2 )) def load_config(): ensure_dirs() try: return json.loads(CONFIG_FILE.read_text())The documented configuration directs users to place the credential directly in this file:
json { "slugs": ["your-skill-slug"], "plugins": ["@you/your-plugin"], "anthropic_api_key": "sk-ant-..." }Technical Analysis
Path.mkdir()andPath.write_text()do not explicitly enforce owner-only permissions. Their effective permissions depend on the process umask. Under a common umask of022, the directory may be created as0755and the configuration file as0644, allowing other local users to read the plaintext Anthropic API key.The documentation claims that the file is created with “default user-only permissions by the OS,” but the implementation does not guarantee that property. It also does not inspect or repair the permissions of an existing configuration file. This violates least-privilege credential handling and creates a local credential-disclosure risk.
Sending the key in the
x-api-keyHTTPS header to Anthropic is necessary for the explicitly enabled--deepfeature and is not itself unauthorized exfiltration. The vulnerability is the persistent plaintext storage without enforced access controls.Attack Path
- A user runs Skill Doctor, causing
~/.skill-doctor/config.jsonto be created under the user's current umas ...[truncated 992 chars]
- A user runs Skill Doctor, causing
- Remediation
View remediation
Remediation Suggestions
- Create the configuration directory with mode
0700and the configuration file with mode0600. - After creation, explicitly apply
chmod(0o700)to the directory andchmod(0o600)to the file rather than relying on the current umask. - Validate permissions whenever the configuration is loaded. Refuse to use an overly permissive credential file or repair it after warning the user.
- Prefer obtaining the key from an environment variable such as
ANTHROPIC_API_KEYor from an operating-system credential store. - If file-based storage remains supported, write updates atomically through an owner-only temporary file and then replace the destination.
- Correct the documentation so it does not claim that the operating system automatically guarantees user-only permissions.
Example hardening:
python import os def ensure_dirs(): CONFIG_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) os.chmod(CONFIG_DIR, 0o700) STATE_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) os.chmod(STATE_DIR, 0o700) if not CONFIG_FILE.exists(): fd = os.open(CONFIG_FILE, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(fd, "w") as config: json.dump( {"slugs": [], "plugins": [], "anthropic_api_key": None}, config, indent=2, ) else: os.chmod(CONFIG_FILE, 0o600)- Create the configuration directory with mode
