T09 · Insecure Skill Coding Practices
- Location
- README.md:39
- Finding
- Plaintext X/Twitter credentials exposed through agent conversations, command-line arguments, and configuration files<![CDATA[ ## Vulnerability Details **File Location**: `README.md:39-44`, `README.md:52-69`, `config.example.json:1-8`, `scripts/x_auth.py:58-84`, `scripts/x_auth.py:96-101`, `scripts/x_utils.py:26-44` **Vulnerability Type**: Plaintext credential handling and insecure secret storage **Risk Level**: High ### Vulnerable Code and Documentation `README.md:39-44` instructs users to disclose their account password directly to an AI agent: ```markdown ### 🤖 Or Let Your AI Agent Do It If you're using an AI agent (OpenClaw, Claude Code, etc.), just say: > "Install x-cli from https://github.com/ignsoftwarellc/x-cli — my X username is **your_username**, password is **your_password**." ``` `README.md:52-69` recommends passing the password on the command line or storing it in plaintext configuration: ```markdown ### Option 1: Login with credentials ```bash python scripts/x_auth.py login --username your_user --password your_pass ``` ### Option 2: Use existing cookies If you already have a `cookies.json` file (e.g. from a browser export), place it in the project root. ### Option 3: Set credentials in config.json ```json { "x_username": "your_username", "x_email": "your_email@example.com", "x_password": "your_password", "cookies_file": "cookies.json", "proxy": null, "language": "en-US" } ``` ``` `config.example.json:1-8` establishes plaintext password storage as a supported default configuration pattern: ```json { "cookies_file": "cookies.json", "proxy": null, "x_username": "", "x_email": "", "x_password": "", "language": "en-US" } ``` `scripts/x_auth.py:58-84` reads the password from either a command-line argument or plaintext configuration and then saves authenticated cookies: ```python async def cmd_login(args): config = load_config() username = args.username or config.get("x_username") password = args.password or config.get("x_password") email = args.email or config.get("x_email", username) if not usern ...[truncated 4567 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove all instructions asking users to submit passwords in AI-agent conversations. 2. Remove or deprecate the `--password` command-line argument. 3. If password authentication must remain available, acquire the password interactively with Python's `getpass.getpass()` so it is not echoed or placed in shell history. 4. Prefer a browser-assisted authorization flow, OAuth, or user-provided cookies over persistent account-password storage. 5. Do not support `x_password` in `config.json`. If unattended authentication is essential, integrate with an operating-system credential store or a dedicated secret manager. 6. Create cookie files with owner-only permissions and verify permissions after `twikit` writes them: ```python cookies_path.chmod(0o600) ``` 7. Validate that the configured cookie path resolves to an intended private location and does not traverse outside the approved data directory. 8. Add `config.json`, `cookies.json`, and equivalent secret files to `.gitignore`. 9. Document that agent transcripts, execution traces, shell history, and backups must never contain credentials. 10. Recommend revoking sessions and changing the account password if credentials were previously supplied through the documented insecure methods. ]]>
