T09 · Insecure Skill Coding Practices
- Location
scripts/submit-draft.js:463- Finding
WeChat Access Token Persisted in Plaintext
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent WeChat article workflow, but its draft submission script can expose local files and stores a live WeChat access token in plaintext.
Review this skill before installing. It needs WeChat account credentials and can submit drafts and upload article assets. Do not run it on untrusted HTML, and avoid using it in workspaces containing sensitive images until image path confinement is fixed. Treat generated draft.json files as sensitive because the current script stores a WeChat access token there.
scripts/submit-draft.js:463WeChat Access Token Persisted in Plaintext
scripts/submit-draft.js:262Unrestricted HTML Image Paths Can Upload Files Outside the Article Directory
scripts/temp-convert.js:47Sandbox-Disabled Chromium Renders Caller-Supplied Active HTML
The trigger condition is extremely broad, instructing immediate use whenever a user mentions common article-related phrases. This can cause unintended activation in ordinary conversation and may launch a workflow that performs research, content generation, file creation, and eventual external publication steps without sufficiently explicit user intent for this specific skill.
The lockfile includes basic-ftp 5.2.0, which is flagged for FTP command injection and denial-of-service issues. In this dependency graph it is only pulled in transitively via get-uri/pac-proxy-agent/proxy-agent for proxy handling, so exposure depends on whether the application processes attacker-controlled FTP/PAC URIs or proxy settings; that makes the issue real but likely less directly reachable from normal Puppeteer usage.
extract-zip 2.0.1 is present and has reported symlink/path traversal issues that can lead to arbitrary file writes during archive extraction. Because Puppeteer and @puppeteer/browsers use archive download/extraction flows for browser binaries, this becomes more relevant than a dormant library issue if untrusted archives, mirrors, or manipulated downloads are ever processed.
ip-address 10.1.0 is reported with parsing and HTML-emission issues. In this tree it is a transitive dependency of socks, used by socks-proxy-agent/proxy-agent, so the vulnerable functionality may only matter if the application accepts attacker-controlled proxy configuration or renders library-produced HTML; otherwise practical exploitability is limited.
js-yaml 4.1.1 is included with advisories for CPU-exhaustion via crafted YAML structures. In this dependency graph it comes from cosmiconfig, which means the danger depends on whether the tool loads YAML configuration from untrusted sources; for a CLI/automation skill that may read local config, this is a plausible denial-of-service vector rather than remote code execution.
ws 8.20.0 is flagged for memory disclosure and memory exhaustion issues. Since Puppeteer relies on WebSocket communication with Chromium via puppeteer-core, malformed or attacker-influenced WebSocket traffic could affect confidentiality or availability if the debugging connection is exposed, proxied, or otherwise reachable by untrusted parties.
The script persists the access token into draft.json on disk, creating a local plaintext credential artifact that may be readable by other users, backup systems, logs, or later tools. In a skill/agent environment this is especially risky because workspace files are often inspected, uploaded, or retained automatically, turning a short-lived token into a broader credential exposure.
The skill integrates with external services including the WeChat Official Account API and Feishu documents, and it culminates in draft submission, but the top-level description does not clearly warn that user content may be transmitted to third parties. In a content-production skill, this increases the risk of users unintentionally disclosing unpublished, sensitive, or proprietary material to external platforms.
The document title and all instructions are written exclusively in Chinese, presenting the style guide as a fixed language-specific standard rather than offering language selection. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is clearly documented and justified.
The file explicitly defines itself as a Chinese AI text detector and all detection patterns, CLI description, and output strings are hard-coded for Chinese text only. There is no user choice of language or locale, so the skill imposes a specific language behavior rather than offering opt-in or documenting a justified regional constraint.
The module description states that it humanizes Chinese AI-generated text, and the rest of the CLI/help text is also fixed to Chinese. Under the policy rule for language or locale constraints, this is a natural-language locale restriction without an explicit user language choice or justification as a region-specific tool.
The module docstring describes a Chinese AI text humanizer focused on text transformations such as sentence restructuring and replacement. However, the optional style feature invokes an external script via subprocess, introducing process-execution capability beyond the stated text-processing purpose in this file's documentation.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
tmp_path = tmp.name
try:
proc = subprocess.run(
['python3', style_script, tmp_path, '--style', args.style],
capture_output=True, text=True, encoding='utf-8'
)
This JSON file is entirely specialized to Chinese phrases, regexes, and Chinese-language descriptions, which indicates the skill behavior is constrained to a specific language/locale. Under the policy, forcing a specific language without explicit user choice or a clearly documented justification can be a natural-language policy violation.
The module description states that it transforms text into different Chinese writing styles, which imposes a fixed language/locale behavior. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the constraint is clearly documented as a justified region-specific limitation or the user is given a choice.
The script reads WeChat credentials not only from explicit environment variables but also from a separate ~/.openclaw/env file, widening the trust boundary and potentially using secrets from an unrelated local context without clear user consent. In an agent/skill setting, this can cause unintended credential harvesting or cross-project secret use if the skill is run on a host that already has OpenClaw credentials configured.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
console.log('正在获取access_token...');
const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
try {
const response = await fetch(apiUrl, {
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
console.log('正在获取access_token...');
const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
try {
const response = await fetch(apiUrl, {
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
console.log('正在获取access_token...');
const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
try {
const response = await fetch(apiUrl, {
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
console.log('正在获取access_token...');
const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
try {
const response = await fetch(apiUrl, {
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
console.log('正在获取access_token...');
const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
try {
const response = await fetch(apiUrl, {
The markdown explicitly instructs the skill to prioritize Chinese sources (优先中文源). This is a natural-language locale constraint that does not offer the user a choice or explain a region-specific necessity, which fits the language/locale policy violation criteria.
The skill instructs the agent to create a Feishu document and send the resulting document or link to the user without any explicit user consent step or warning that research content will be shared to an external third-party service. If the research includes sensitive prompts, internal notes, proprietary data, or user-provided content, this can cause unintended data disclosure outside the primary interaction channel.
This markdown file instructs the user exclusively in Chinese, from the title through the output instructions, with no indication that language preference is optional. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation unless clearly justified.
This markdown file presents all operational instructions and acceptance criteria exclusively in Chinese. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.
Detected: suspicious.env_credential_access