T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/capabilities/configure/service.py:42
- Finding
- Access Key Stored in Plaintext Without Enforced File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/capabilities/configure/service.py:42-64` **Vulnerability Type**: Plaintext sensitive-data storage with insufficient permission enforcement **Risk Level**: Medium ### Vulnerable Code ```python def configure_via_file(api_key: str) -> bool: try: config: dict = {} if CONFIG_PATH.exists(): try: with open(CONFIG_PATH, "r", encoding="utf-8") as f: content = f.read().strip() if content: config = json.loads(content) except json.JSONDecodeError: return False config.setdefault("skills", {}) config["skills"].setdefault("entries", {}) config["skills"]["entries"].setdefault(SKILL_NAME, {}) skill_entry = config["skills"]["entries"][SKILL_NAME] skill_entry["apiKey"] = api_key if "env" in skill_entry and isinstance(skill_entry["env"], dict): skill_entry["env"].pop("ALI_1688_AK", None) if not skill_entry["env"]: del skill_entry["env"] CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True) with open(CONFIG_PATH, "w", encoding="utf-8") as f: json.dump(config, f, ensure_ascii=False, indent=2) return True except Exception: return False ``` ### Technical Analysis When gateway-based configuration is unavailable, the Skill falls back to writing the merchant Access Key to `openclaw.json`. The credential is stored as plaintext in the `apiKey` property. The code creates the parent directory and writes the file using ordinary Python file operations, but it does not set or verify restrictive permissions. Consequently, the effective access controls depend on the process umask and any pre-existing directory or file permissions. If those permissions allow access by other local users or processes, the credential can be disclosed. This exceeds secure minimu ...[truncated 1579 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Prefer an operating-system credential store or the OpenClaw secret-management mechanism instead of plaintext JSON storage. 2. If file fallback remains necessary: - Create the configuration directory with mode `0700`. - Create the configuration file atomically with mode `0600`. - Verify and correct permissions on pre-existing files before writing. - Reject symbolic links and unexpected non-regular files. 3. Write to a securely created temporary file in the same directory, apply restrictive permissions, flush it, and atomically replace the destination. 4. Avoid silently falling back to insecure storage. Inform the user when secure gateway storage is unavailable and require explicit consent before plaintext file storage. 5. Document the credential location, protection model, and rotation procedure. 6. Recommend immediate AK rotation if unauthorized filesystem access is suspected. ]]>
