T09 · Insecure Skill Coding Practices
- Location
SKILL.md:330- Finding
Bearer Token Stored in a Plaintext File Without Enforced Access Restrictions
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 330–341
Vulnerability Type: Plaintext credential storage with umask-dependent permissions
Risk Level: MediumVulnerable Code
python CRED_PATH = os.path.expanduser("~/.config/agent-chatroom/credentials.json") # 1. Create bot bot = requests.post(f"{BASE}/bot/create", json={"bot_name": "MyAgent"}).json() TOKEN = bot["token"] CLAIM_URL = bot.get("claim_url", "") HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} # Save credentials os.makedirs(os.path.dirname(CRED_PATH), exist_ok=True) with open(CRED_PATH, "w") as f: json.dump({"token": TOKEN, "bot_name": "MyAgent"}, f)The Skill also recommends this plaintext credential location at line 74:
markdown **Recommended:** Save your credentials to `~/.config/agent-chatroom/credentials.json`:Technical Analysis
The quick-start example writes the OpenRoom bearer token to an ordinary JSON file. Neither the credential directory nor the file is created with explicit owner-only permissions. Their effective permissions therefore depend on the user's process umask and any pre-existing filesystem object at the path.
Under a permissive or misconfigured umask, the credential file may be readable by other local users or processes. The use of regular
open(..., "w")also follows symbolic links, so the example does not protect against unsafe pre-existing path conditions.Sending the token in an
Authorizationheader to the declared HTTPS OpenRoom API is necessary for authenticated operations and does not by itself indicate exfiltration. The security issue is the avoidable plaintext persistence of that reusable token without enforced access controls.Attack Path
- A user runs the documented Python quick-start example.
- The Skill receives a reusable bearer token from the OpenRoom
/bot/createendpoint. - The example creates `~/.config/ ...[truncated 1152 chars]
- Remediation
View remediation
Remediation Suggestions
- Prefer an operating-system credential manager or secret-storage service instead of a plaintext JSON file.
- If file storage is required, create the configuration directory with mode
0700and the credential file atomically with mode0600. - Refuse unsafe pre-existing files and symbolic links where the platform supports this.
- Avoid recommending general agent memory as a token-storage location unless that storage has explicit confidentiality guarantees.
- Document token revocation and rotation procedures.
A hardened file-based implementation could use exclusive creation and explicit permissions:
python import json import os cred_dir = os.path.expanduser("~/.config/agent-chatroom") cred_path = os.path.join(cred_dir, "credentials.json") os.makedirs(cred_dir, mode=0o700, exist_ok=True) os.chmod(cred_dir, 0o700) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(cred_path, flags, 0o600) try: with os.fdopen(fd, "w", encoding="utf-8") as credential_file: json.dump({"token": TOKEN, "bot_name": "MyAgent"}, credential_file) except Exception: try: os.unlink(cred_path) except FileNotFoundError: pass raiseIf credentials must be updated, write them to a securely created owner-only temporary file in the same protected directory and replace the destination atomically after validating that the destination is not an unsafe link.
