T09 · Insecure Skill Coding Practices
- Location
test-smtp.js:36- Finding
Hard-Coded SMTP Account Credential
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This stock-report email skill has a coherent purpose, but it needs review because it mishandles mail credentials and can make persistent system and scheduler changes.
Do not install this as-is for a real mailbox. Before use, remove the hard-coded recipient and test credential, rotate any exposed SMTP password, store mail secrets in a protected secret manager or tightly permissioned config file, stop logging credential-bearing configuration, keep TLS certificate validation enabled, avoid the sudo hosts-file helper, and review any cron or shell-profile persistence before enabling it.
test-smtp.js:36Hard-Coded SMTP Account Credential
index.js:269SMTP Password Disclosure Through Console and Cron Logs
index.js:276SMTP Certificate Validation Is Disabled
fix-hosts.sh:8Root-Level Persistent SMTP DNS Overrides
send-mail-applescript.js:17Shell and AppleScript Injection in Alternate Mail Sender
index.js:324Predictable Temporary Files Permit Symlink and Race Attacks
setup.sh:79SMTP Secrets Persisted in Environment Files and Shell Startup Profiles
config.js:52Configuration Input Is Written Directly Into Executable JavaScript
index.js:53Market Data Is Retrieved Over Plaintext HTTP and Embedded Without HTML Escaping
package-lock.json:15Dependency Lockfile Uses a Non-Default Package Mirror
The documentation instructs users to place SMTP credentials, including the mailbox username and password, into a .env file in plaintext. While common in development, this is dangerous because plaintext secrets are easily exposed through accidental commits, weak file permissions, shell history, backups, or local compromise.
文件位置:.env
# 编辑 .env 文件,将 YOUR_PASSWORD_HERE 替换为你的邮箱密码
SMTP_CONFIG={"host":"smtp.qiye.aliyun.com","port":465,"secure":true,"user":"8@batype.com","pass":"你的密码","from":"8@batype.com"}
The instruction source .env && node index.js loads secrets into the shell environment, increasing exposure to subprocess inheritance, debugging output, and accidental leakage during interactive use. In a skill context, this also normalizes handling credentials in an unsafe way without discussing protections.
cd /Users/batype/.openclaw/workspace-work/skills/astock-daily
source .env && node index.js
### 预期输出
Repeating the source .env && node index.js pattern reinforces insecure credential handling and increases the chance that users will expose secrets in shell sessions or automation. The danger is amplified because the file specifically contains SMTP authentication material.
测试运行:
cd /Users/batype/.openclaw/workspace-work/skills/astock-daily
source .env && node index.js
Sourcing .env imports all variables into the current shell session, which commonly includes credentials such as SMTP usernames, passwords, API keys, or tokens. In combination with running the application, this can expose secrets to logs, child processes, shell history patterns, or unintended code paths, making it more dangerous in an automation skill that users may trust and execute directly.
cd /Users/batype/.openclaw/workspace-work/skills/astock-daily source .env && node index.js
---
This step explicitly instructs the user to edit a .env file and insert their actual email password in plaintext. In the context of a skill repository, that is sensitive credential material that can be leaked via source control, local file exposure, backups, or accidental sharing, making the issue more dangerous than a generic configuration example.
编辑 .env 文件:
cd /Users/batype/.openclaw/workspace-work/skills/astock-daily
vi .env
将 YOUR_PASSWORD_HERE 替换为你的邮箱密码:
Using source .env && node index.js loads the secret into the current shell environment, which broadens exposure of the credential to child processes, shell debugging, process inspection in some environments, and user mistakes during troubleshooting. Combined with the prior instruction to store the password in plaintext, this creates a practical credential-handling weakness.
cd /Users/batype/.openclaw/workspace-work/skills/astock-daily
source .env && node index.js
检查邮箱是否收到邮件!
The README instructs users to place an SMTP password directly into a .env file and even includes a real-looking corporate email account in the sample configuration. Storing credentials in plaintext increases the risk of accidental disclosure through local file compromise, shell history, backups, screenshots, or committing the file to version control.
# 编辑文件
vi .env
# 将 YOUR_PASSWORD_HERE 替换为你的邮箱密码
SMTP_CONFIG={"host":"smtp.qiye.aliyun.com","port":465,"secure":true,"user":"8@batype.com","pass":"你的密码","from":"8@batype.com"}
At this point the script persists SMTP_CONFIG containing host, username, and password/auth code to a .env file in plaintext. Because these credentials enable authenticated access to an email-sending account, exposure can lead to account abuse, spam, phishing, mailbox-related compromise, and possible pivoting into other systems that trust that mailbox.
console.log('\n或者添加到 ~/.zshrc 或 ~/.bashrc:');
console.log(` export SMTP_CONFIG='${JSON.stringify(smtpConfig)}'`);
// 保存到 .env 文件
const envPath = path.join(__dirname, '.env');
fs.writeFileSync(envPath, `SMTP_CONFIG=${JSON.stringify(smtpConfig)}\n`);
console.log(`\n💾 配置已保存到:${envPath}`);
This finding is effectively the same underlying issue: the generated configuration string includes live SMTP credentials and is then written to a .env file. In the context of a skill setup helper, users may trust the wizard and store sensitive mail credentials locally without realizing the exposure risk, making credential theft more likely through routine development practices.
console.log(` export SMTP_CONFIG='${JSON.stringify(smtpConfig)}'`);
// 保存到 .env 文件
const envPath = path.join(__dirname, '.env');
fs.writeFileSync(envPath, `SMTP_CONFIG=${JSON.stringify(smtpConfig)}\n`);
console.log(`\n💾 配置已保存到:${envPath}`);
}
The lockfile pins nodemailer to version 6.10.1, and the finding indicates multiple published advisories affecting that version, including header injection, denial of service, and security-control bypass issues. Because this is a dependency manifest rather than dead code, the vulnerable package is very likely to be installed and used by the skill at runtime, making this a true supply-chain vulnerability unless mitigations are separately proven.
The project depends on nodemailer in a version range that can include known vulnerable releases, and this skill's stated purpose includes sending email, making the dependency directly relevant to runtime behavior. If a vulnerable version is installed, issues such as header injection, denial of service, or file/content access bypasses could be exploitable through crafted mail inputs or message construction.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 添加新任务
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CRON_LINE="30 9 * * 1-5 cd $SCRIPT_DIR && source .env && /opt/homebrew/bin/node index.js >> /tmp/astock-daily.log 2>&1"
# 添加到 crontab
(echo "$CURRENT_CRON"; echo "$CRON_LINE") | crontab -
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 添加新任务
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CRON_LINE="30 9 * * 1-5 cd $SCRIPT_DIR && source .env && /opt/homebrew/bin/node index.js >> /tmp/astock-daily.log 2>&1"
# 添加到 crontab
(echo "$CURRENT_CRON"; echo "$CRON_LINE") | crontab -
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 添加新任务
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CRON_LINE="30 9 * * 1-5 cd $SCRIPT_DIR && source .env && /opt/homebrew/bin/node index.js >> /tmp/astock-daily.log 2>&1"
# 添加到 crontab
(echo "$CURRENT_CRON"; echo "$CRON_LINE") | crontab -
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 添加新任务
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CRON_LINE="30 9 * * 1-5 cd $SCRIPT_DIR && source .env && /opt/homebrew/bin/node index.js >> /tmp/astock-daily.log 2>&1"
# 添加到 crontab
(echo "$CURRENT_CRON"; echo "$CRON_LINE") | crontab -
At this point the script writes SMTP credentials into a .env file in plaintext. Secrets stored this way are easy to exfiltrate by any local process with access to the working directory, may be accidentally committed to source control, and can persist long after the user expects.
echo ""
echo "⚙️ 正在保存配置..."
# 保存到 .env 文件
cat > .env << EOF
SMTP_CONFIG='$SMTP_CONFIG'
EOF
The script stores entered email credentials in plaintext in .env and may also append them to shell startup files without warning about the sensitivity of those actions. Plaintext secret storage makes credential theft easier through local compromise, backups, shell history exposure via sourced environments, or accidental inclusion in version control.
This finding reflects the same credential-write operation into .env, which contains the SMTP username and password. Persisting mail credentials in plaintext unnecessarily creates a durable credential exposure point and increases the blast radius of any local compromise.
echo "⚙️ 正在保存配置..."
# 保存到 .env 文件
cat > .env << EOF
SMTP_CONFIG='$SMTP_CONFIG'
EOF
The script confirms that configuration has been saved to .env, reinforcing that credentials are intentionally persisted in plaintext. In the context of an automation/setup script, this is especially dangerous because users may run it in project directories that are shared, backed up, or version-controlled.
SMTP_CONFIG='$SMTP_CONFIG'
EOF
echo "✅ 配置已保存到 .env 文件"
# 添加到 shell 配置文件
SHELL_RC=""
This markdown file instructs users to run crontab -r, which deletes all cron jobs for the user, but the surrounding guidance does not clearly warn about the irreversible impact beyond a brief parenthetical. Under the markdown warning criteria, destructive behavior affecting system configuration should be explicitly disclosed so users understand the risk before running it.
This is a markdown file, so SQP-2 applies to user-facing documentation. The instructions explicitly tell the user to delete the old task before adding a new one, but they do not warn that openclaw cron rm is a destructive action that removes the existing schedule and may interrupt automation if re-creation fails.
The document instructs users to append entries to /etc/hosts using sudo, which makes persistent system-level networking changes with elevated privileges. Even if the goal is legitimate troubleshooting, the guidance lacks warnings about privilege use, rollback steps, and the risk of hard-coding DNS results that may become stale or redirect traffic incorrectly.
This command uses sudo to modify /etc/hosts, a privileged system configuration file controlling name resolution. If copied without scrutiny, users grant elevated privileges to a shell command that permanently alters network behavior and could enable traffic redirection or operational breakage.
或手动执行:
sudo sh -c 'echo "47.246.165.89 smtp.qiye.aliyun.com" >> /etc/hosts'
sudo sh -c 'echo "47.246.165.89 smtp.mxhichina.com" >> /etc/hosts'
This is a second privileged /etc/hosts modification for another mail domain, carrying the same risk of persistent DNS override under root privileges. Hard-coded mail server IPs can also age poorly and silently redirect mail traffic if infrastructure changes.
sudo sh -c 'echo "47.246.165.89 smtp.qiye.aliyun.com" >> /etc/hosts'
sudo sh -c 'echo "47.246.165.89 smtp.mxhichina.com" >> /etc/hosts'
The validation step sources the local .env file and immediately runs the application, which can expose sensitive credentials into the current shell and execute behavior dependent on secrets without any cautionary note. In a skill context, this is risky because users may run it blindly and leak or misuse SMTP credentials stored in .env.
Detected: suspicious.dangerous_exec, suspicious.insecure_tls_verification