T09 · Insecure Skill Coding Practices
Warning
- Location
- wp_oauth_skill.py:148
- Finding
- OAuth Secrets Exposed Through Process Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `wp_oauth_skill.py:148-151`, `wp_oauth_skill.py:281-286`; documented usage in `SKILL.md:32-38` **Vulnerability Type**: Sensitive information exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python def exchange_token(args: argparse.Namespace) -> dict[str, Any]: client_id = get_required(args.client_id, "WPCOM_CLIENT_ID", "--client-id") client_secret = get_required( args.client_secret, "WPCOM_CLIENT_SECRET", "--client-secret" ) redirect_uri = get_required( args.redirect_uri, "WPCOM_REDIRECT_URI", "--redirect-uri" ) code = args.code callback_state = args.state if args.callback_url: parsed_code, parsed_state, oauth_error = parse_callback(args.callback_url) ``` ```python p_exchange.add_argument("--client-id", default=None) p_exchange.add_argument("--client-secret", default=None) p_exchange.add_argument("--redirect-uri", default=None) p_exchange.add_argument("--callback-url", default=None) p_exchange.add_argument("--code", default=None) p_exchange.add_argument("--state", default=None) ``` The documented command encourages supplying these values as command-line arguments: ```bash python3 {baseDir}/wp_oauth_skill.py exchange-token \ --client-id "$WPCOM_CLIENT_ID" \ --client-secret "$WPCOM_CLIENT_SECRET" \ --redirect-uri "$WPCOM_REDIRECT_URI" \ --callback-url "https://example/callback?code=...&state=..." ``` ### Technical Analysis The OAuth client secret, authorization code, and complete callback URL are accepted through command-line flags. Shell variable expansion occurs before process creation, so the expanded values can appear in the Python process argument vector. Depending on the operating system and execution environment, command-line arguments may be exposed through process-monitoring interfaces, diagnostic tooling, shell tracing, terminal or session recording, job-runner logs, and command-history workflows. ...[truncated 2128 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Implement the advertised environment-variable fallback rather than merely mentioning it in the error message: ```python import os def get_required(value: str | None, env_name: str, flag_name: str) -> str: resolved = value or os.environ.get(env_name) if resolved: return resolved raise SkillError( f"Missing required value. Provide {flag_name} or set {env_name}." ) ``` 2. Prefer reading the client secret from a protected environment variable, standard input, a secret manager, or `getpass.getpass()` instead of a command-line option. 3. Allow the callback URL or authorization code to be supplied through standard input or a protected file descriptor. 4. Update `SKILL.md` so the recommended command does not include secret-bearing flags. 5. Retain command-line secret options only if compatibility requires them, and display an explicit warning that process arguments may be logged or visible locally. 6. Ensure CI systems and process supervisors do not log expanded commands or environment variables containing OAuth material. 7. Clear temporary references to authorization codes and avoid including them in errors or debug output. ]]>
