T09 · Insecure Skill Coding Practices
- Location
SKILL.md:42- Finding
Mailbox Credentials Exposed Through Shell Command Examples
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 42, 48, 60, and 68
Vulnerability Type: Credentials embedded in shell command arguments
Risk Level: MediumVulnerable Code
bash echo '{"email":"user@163.com","password":"authorization-code"}' | python scripts/test_connection.pybash echo '{"email":"user@corp.com","password":"pass","imap_host":"imap.corp.com","smtp_host":"smtp.corp.com"}' | python scripts/test_connection.pybash echo '{"email":"...","password":"...","imap_host":"imap.163.com","imap_port":993,"folder":"INBOX","limit":20,"unread_only":false}' | python scripts/list_emails.pybash echo '{"email":"...","password":"...","imap_host":"imap.163.com","uid":"1234","mark_as_read":true}' | python scripts/read_email.pybash echo '{"email":"...","password":"...","smtp_host":"smtp.163.com","smtp_port":465,"to":"recipient@example.com","subject":"subject","body":"message body"}' | python scripts/send_email.pyTechnical Analysis
The scripts correctly read JSON from standard input, but the documented invocation pattern places the complete JSON document—including the mailbox authorization code, application password, or enterprise mailbox password—inside an
echocommand argument.When users replace the placeholders with real credentials, the secret may be:
- Persisted in interactive shell history.
- Captured by terminal or session-recording systems.
- Collected by command telemetry and audit logging.
- Temporarily visible through local process inspection while
echois running. - Exposed in copied command transcripts, troubleshooting records, or automation logs.
This undermines the intended security benefit of accepting credentials through standard input. Mailbox application passwords and authorization codes can grant both IMAP and SMTP access and therefore must be handled as authentication secrets.
Attack Path
- A user follows the examples in
SKILL.md. - The user replaces the passwo ...[truncated 1429 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace command examples containing credential placeholders in shell arguments with an interactive launcher that reads secrets using Python's
getpass.getpass()or an equivalent no-echo prompt. - Pass the secret directly to the target process through a protected file descriptor or pipe without first placing it in a command argument.
- Support retrieving credentials from an operating-system keychain or managed secret store.
- If a temporary configuration file is unavoidable, create it with owner-only permissions, avoid predictable paths, and delete it immediately after use.
- Add an explicit warning that real passwords, authorization codes, and application passwords must never be entered directly into shell command lines.
- Document credential rotation and revocation procedures in case a secret has already been entered using the existing examples.
- Ensure wrappers and automation do not print the input JSON or include it in debug, CI, telemetry, or exception logs.
- Prefer a usage pattern such as an interactive wrapper:
python import getpass import json import subprocess email = input("Email: ").strip() password = getpass.getpass("Authorization code or app password: ") payload = { "email": email, "password": password, } subprocess.run( ["python", "scripts/test_connection.py"], input=json.dumps(payload), text=True, check=False, )This keeps the credential out of the shell command line and prevents terminal echo during entry.
- Replace command examples containing credential placeholders in shell arguments with an interactive launcher that reads secrets using Python's
