T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/onboarding.py:507
- Finding
- Authentication Secrets Exposed Through Command-Line Arguments and Standard Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/onboarding.py`, lines 467-493, 507-510, and 574-579 **Vulnerability Type**: Exposure of authentication secrets through process arguments and output channels **Risk Level**: High ### Vulnerable Code ```python def login_and_get_key(phone: str, code: str, channel: str) -> dict: masked = _mask_phone(phone) if not re.fullmatch(r"\d{11}", phone): return {"error": f"login: Invalid phone number format: {phone}", "phone": masked} if not re.fullmatch(r"\d{4,8}", code): return {"error": f"login: Invalid verification code format: {code}", "phone": masked} lg = _login_v3(phone, code, channel) if "error" in lg: return {"error": lg["error"], "phone": masked} if lg.get("is_new_user"): lbt = _login_by_token(lg["access_token"], lg["refresh_token"]) if "error" in lbt: print(f"{TAG} {lbt['error']}", file=sys.stderr) info = _fetch_user_info_v3(lg["access_token"], lg["user_id"]) if "error" in info: return {"error": info["error"], "phone": masked} tok = _get_or_generate_api_token( lg["access_token"], lg["user_id"], info["group_id"] ) if "error" in tok: return {"error": tok["error"], "phone": masked} return { "api_key": tok["api_key"], "phone": masked, "group_id": info["group_id"], "member_id": info["member_id"], "source": tok["source"], "nick_name": lg.get("nick_name", ""), "team_name": info.get("team_name", ""), "is_new_user": lg.get("is_new_user", False), } ``` ```python def _cmd_login(args) -> int: r = login_and_get_key(args.phone.strip(), args.code.strip(), args.channel) _emit(r) if "api_key" in r: print(f"{TAG} API key obtained successfully", file=sys.stderr) return 0 return 1 ``` ```python p = sub.add_parser("login", help="Log in using a verification code and obtain an API key") p.add_argument ...[truncated 2415 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Read the SMS verification code using a non-echoing interactive prompt such as `getpass.getpass()` or accept it through standard input rather than a command-line argument. 2. Do not include the complete API key in stdout JSON. Return only a masked fingerprint, such as the first and last four characters. 3. Store the API key directly in an operating-system credential manager or a file created with mode `0600`. 4. If machine-readable secret output is unavoidable, require an explicit opt-in flag and write the secret to a caller-specified file descriptor rather than ordinary stdout. 5. Add prominent documentation warning that credentials must not be entered into shared terminals, chat transcripts, or CI command lines. 6. Ensure error messages never serialize complete authentication responses containing access tokens, refresh tokens, API keys, or verification codes. 7. Review the server-side key scope and issue a least-privilege key limited to the catalog operations required by this Skill. ]]>
