Back to skill

Security audit

Pharmaceutical Bidding

Security checks for vulnerabilities and agentic risk

Overview

The skill fits its bidding-collection purpose, but it exposes WeCom secrets in logs, sends business data automatically, and includes unsafe scheduling/install patterns that require review before use.

Review and fix the WeCom secret logging before installing. Use least-privilege WeCom credentials, restrict webhook destinations to approved WeCom endpoints, add a dry-run or approval step before records or notifications are sent, and choose one scheduler model instead of installing the supplied crontab alongside the in-process scheduler.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
validate-wecom-config.js:143
Finding
Plaintext Disclosure of WeCom Authentication and Encryption Secrets<![CDATA[ ## Vulnerability Details **File Location**: `validate-wecom-config.js:143-144` **Vulnerability Type**: Sensitive information exposure through console output **Risk Level**: High ### Vulnerable Code ```javascript console.log('3. Configure the message receiving server:'); console.log(' - URL: ' + wechatConfig.url); console.log(' - Token: ' + wechatConfig.token); console.log(' - EncodingAESKey: ' + wechatConfig.encodingAesKey); console.log('4. Save the configuration'); ``` ### Technical Analysis The validation utility reads WeCom configuration from a workspace-level `openclaw.json` file and prints the complete callback token and EncodingAESKey to standard output. These values are authentication and cryptographic secrets. Standard output is not an appropriate secret-handling channel because it may be captured by: - Terminal session recording - CI/CD logs - Centralized logging systems - Shell wrappers and process supervisors - Agent execution transcripts - Shared troubleshooting output The secret disclosure is unnecessary for configuration validation. The utility only needs to confirm whether the fields exist and whether the EncodingAESKey has the expected length. ### Attack Path 1. A user stores valid WeCom callback credentials in `openclaw.json`. 2. The user or an automated process runs `node validate-wecom-config.js`. 3. The script reads the workspace-level configuration file. 4. The complete callback Token and EncodingAESKey are written to standard output. 5. An attacker with access to retained terminal, CI, supervisor, or agent logs retrieves the values. 6. The disclosed material may be used to forge callback signatures or compromise the confidentiality of callback processing, depending on the surrounding WeCom integration. ### Impact Assessment The vulnerability does not independently grant operating-system privileges. It exposes credentials within the WeCom integration boundary. Potential impact includes: - Disclosure of callback a ...[truncated 449 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all output containing full tokens, secrets, encryption keys, or credentials. 2. Report only whether each secret is configured: ```javascript console.log(' - Token: configured'); console.log(' - EncodingAESKey: configured and length validated'); ``` 3. If identification is operationally necessary, use a non-secret identifier rather than a partial secret. 4. Require the configuration path to be explicitly supplied instead of automatically searching parent workspace directories. 5. Verify that the configuration file is readable only by the service account, such as mode `0600` on supported systems. 6. Redact secrets from CI logs, error telemetry, debug output, and process-supervisor logs. 7. Rotate the Token and EncodingAESKey if the validator has already been run in an environment where output may have been retained. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
test-wechat.js:77
Finding
Partial Disclosure of a Live WeCom Access Token<![CDATA[ ## Vulnerability Details **File Location**: `test-wechat.js:77-78` **Vulnerability Type**: Bearer-token exposure through test logging **Risk Level**: Medium ### Vulnerable Code ```javascript if (wechatConfig.corpId && wechatConfig.corpSecret) { console.log('\n🔑 Test 4: Retrieve Access Token...'); const token = await wechatAPI.getAccessToken( wechatConfig.corpId, wechatConfig.corpSecret ); console.log(`✅ Access Token retrieved successfully: ${token.substring(0, 20)}...`); } else { console.log('\n⚠️ CorpID and Secret are not configured; skipping token test'); } ``` ### Technical Analysis The test retrieves a live bearer token and writes its first 20 characters to standard output. Partial disclosure is still sensitive because access tokens should be treated as indivisible secrets. Prefixes can assist correlation, token identification, debugging-log attacks, or exploitation when combined with another partial disclosure. The test only needs to verify that a non-empty token was returned. Printing any portion of the value provides no necessary security or functional benefit. ### Attack Path 1. A user configures valid `corpId` and `corpSecret` values. 2. The user runs `node test-wechat.js`. 3. The script submits the credentials to the WeCom token endpoint and receives a live access token. 4. The first 20 characters of the token are printed. 5. The output is retained in terminal, CI, agent, or centralized logs. 6. An attacker with log access obtains the token prefix and may combine it with other leaks or use it to identify and correlate active credentials. ### Impact Assessment The code does not disclose the entire token, so direct token replay is not established from this finding alone. Nevertheless, it weakens bearer-token confidentiality and may contribute to credential reconstruction or correlation attacks. The affected scope is the WeCom access-token context used by the configured corporate application. No local privilege escal ...[truncated 28 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never print any part of an access token. 2. Replace the output with a value-independent success message: ```javascript const token = await wechatAPI.getAccessToken( wechatConfig.corpId, wechatConfig.corpSecret ); if (typeof token !== 'string' || token.length === 0) { throw new Error('The token endpoint returned an empty token'); } console.log('Access Token retrieved successfully'); ``` 3. Redact authorization data and URL query parameters from HTTP debug logs. 4. Prevent test scripts from running automatically in production or CI environments unless explicitly authorized. 5. Rotate tokens or their source credentials if prior logs containing token fragments were exposed outside the trusted operational boundary. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
wechat-api.js:22
Finding
Unrestricted Webhook Destination Permits External Disclosure of Collected Records<![CDATA[ ## Vulnerability Details **File Location**: `wechat-api.js:22-34` **Related Validation**: `validate-config.js:65-84` **Vulnerability Type**: Unrestricted outbound request destination and HTTPS SSRF **Risk Level**: Medium ### Vulnerable Code ```javascript async sendMessage(message, webhookUrl = null) { const url = webhookUrl || this.config.webhookUrl; if (!url) { throw new Error('WeCom Webhook URL is not configured'); } try { const response = await axios.post(url, message, { headers: { 'Content-Type': 'application/json' }, timeout: 10000 }); ``` The configuration validator only checks the protocol and presence of a hostname: ```javascript try { const url = new URL(wechatConfig.webhookUrl); if (url.protocol !== 'https:') { console.log(' ❌ The URL protocol must be HTTPS'); allRequiredFieldsValid = false; } else { console.log(' ✅ The URL protocol is valid (HTTPS)'); } if (!url.hostname) { console.log(' ❌ The URL has no hostname'); allRequiredFieldsValid = false; } else { console.log(` ✅ Hostname: ${url.hostname}`); } } catch (error) { console.log(` ❌ Invalid URL format: ${error.message}`); allRequiredFieldsValid = false; } ``` ### Technical Analysis The network sink accepts either a configured URL or a caller-provided URL and sends the complete message to that destination. It does not enforce the documented WeCom host, `qyapi.weixin.qq.com`. The separate configuration validator requires HTTPS but accepts any HTTPS hostname. More importantly, `sendMessage` does not call that validator, so validation can be bypassed entirely by invoking the API directly. The transmitted Markdown records can contain project names, bidding units, budgets, deadlines, product scope, sales assignment, and project status. Although procurement information may originate from public sources, sales assignments, internal status, and enriched records can be business-sensitive ...[truncated 1595 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce destination validation inside `sendMessage`, immediately before the request. 2. Allow only the documented WeCom endpoint: ```javascript const parsed = new URL(url); if ( parsed.protocol !== 'https:' || parsed.hostname !== 'qyapi.weixin.qq.com' || parsed.pathname !== '/cgi-bin/webhook/send' ) { throw new Error('Unapproved WeCom webhook destination'); } ``` 3. Validate the required webhook query structure without logging its secret key. 4. Remove the per-call `webhookUrl` override unless multi-endpoint support is a documented requirement. 5. Disable or strictly validate redirects so an approved endpoint cannot redirect to an unapproved host. 6. If custom webhook hosts are required, use an explicit administrator-controlled allowlist. 7. Reject loopback, private, link-local, multicast, and metadata-service addresses after DNS resolution. 8. Apply outbound firewall rules so the process can reach only required procurement sites and WeCom API endpoints. 9. Validate configuration during startup and fail closed before any scheduled task is registered. ]]>

T08 · Insecure Dependencies

Warning
Location
package-lock.json:4546
Finding
Unused Puppeteer Dependency Introduces Unnecessary Install-Time Code Execution<![CDATA[ ## Vulnerability Details **File Location**: `package-lock.json:4546-4555` **Related Declaration**: `package.json:20-26` **Vulnerability Type**: Unnecessary dependency lifecycle execution and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```json "dependencies": { "axios": "^1.6.0", "cheerio": "^1.0.0", "node-cron": "^3.0.3", "moment": "^2.29.4", "puppeteer": "^21.0.0" } ``` ```json "node_modules/puppeteer": { "version": "21.11.0", "resolved": "https://registry.npmmirror.com/puppeteer/-/puppeteer-21.11.0.tgz", "integrity": "sha512-9jTHuYe22TD3sNxy0nEIzC7ZrlRnDgeX3xPkbS7PnbdwYjl2o/z/YuCrRBwezdKpbTDTJ4VqIggzNyeRcKq3cg==", "deprecated": "< 24.15.0 is no longer supported", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "1.9.1", "cosmiconfig": "9.0.0", "puppeteer-core": "21.11.0" } } ``` ### Technical Analysis No audited project source file imports Puppeteer, yet it is installed as a production dependency. Its lockfile entry declares an installation script, meaning `npm install` executes package-controlled code and may download browser components. This behavior expands the supply-chain attack surface beyond the minimum privileges required by the current implementation. The locked package is also marked unsupported, and dependencies are resolved through `registry.npmmirror.com`, an additional trust boundary compared with the default npm registry. No evidence was found that Puppeteer itself is malicious. The security issue is the unnecessary exposure to install-time executable behavior and external component retrieval for functionality that the source code does not use. ### Attack Path 1. A user follows the README and runs `npm install`. 2. npm retrieves the locked Puppeteer package from the configured mirror. 3. npm executes Puppeteer's installation lifecycle script. 4. The installer runs with the permissions of the user performing installation and ...[truncated 912 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove Puppeteer from `package.json` if browser automation is not implemented: ```bash npm uninstall puppeteer ``` 2. Regenerate and review `package-lock.json` after removal. 3. If browser automation is later required, use a currently supported, explicitly reviewed version. 4. Pin security-sensitive production dependencies to controlled versions rather than broad ranges. 5. Use an organization-approved package registry and document why any third-party mirror is trusted. 6. Run dependency installation in an isolated, unprivileged build environment without production credentials. 7. Consider `npm ci --ignore-scripts` when lifecycle scripts are not required. 8. If browser binaries are required, provision them separately from a verified artifact repository and check cryptographic integrity. 9. Add software-composition analysis and lockfile-change review to the build process. ]]>

T06 · System Persistence

Warning
Location
crontab.txt:4
Finding
OS Cron Entry Repeatedly Launches Long-Lived Internal Scheduler Processes<![CDATA[ ## Vulnerability Details **File Location**: `crontab.txt:4` **Related Code**: `main.js:270-277`, `main.js:321-327` **Vulnerability Type**: Unsafe composition of persistent scheduling mechanisms **Risk Level**: Medium ### Vulnerable Code ```cron 30 8 * * * cd /home/eio/.openclaw/workspace/skills/pharmaceutical-bidding && npm start >> /home/eio/.openclaw/workspace/skills/pharmaceutical-bidding/logs/cron.log 2>&1 ``` The command starts an application that registers another recurring scheduler: ```javascript startScheduledTask() { // Run every day at 08:30 cron.schedule('30 8 * * *', async () => { console.log('Starting scheduled bidding-information collection task...'); try { await this.executeFullWorkflow(); } catch (error) { console.error('Scheduled task failed:', error.message); } }); } ``` The entry point starts that scheduler and also immediately runs the workflow: ```javascript const collector = new PharmaceuticalBiddingCollector(config); // Start scheduled task collector.startScheduledTask(); // Execute immediately once collector.executeFullWorkflow().catch(console.error); ``` ### Technical Analysis Scheduled execution is explicitly declared functionality, so the presence of scheduling is not covert. However, the provided OS cron entry invokes `npm start`, which launches `main.js`. That process registers a `node-cron` schedule and remains alive waiting for future executions. If the OS crontab entry is installed, another long-lived Node.js process is launched every day. There is no singleton lock, PID check, process supervisor integration, or shutdown mechanism. Consequently, the number of active schedulers can grow over time. Each new process also calls `executeFullWorkflow` immediately, and all previously launched processes retain their own daily schedule. ### Attack Path 1. An administrator installs the supplied `crontab.txt` entry. 2. At 08:30, OS cron invokes `npm start`. 3. `main.js` starts an i ...[truncated 982 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Select exactly one scheduling model: - Use OS cron to invoke a one-shot collection command that exits after completion; or - Run one supervised long-lived process containing `node-cron`. 2. For an OS cron deployment, remove `startScheduledTask()` from the invoked code path. 3. For a long-running deployment, do not install the supplied crontab entry. Use a single service manager with restart controls. 4. Add a lock file, PID lock, or distributed mutex to prevent overlapping workflow execution. 5. Honor `scheduling.enabled`, `scheduling.cron`, and `scheduling.timezone` from configuration instead of hard-coding the schedule. 6. Add graceful signal handling to stop the scheduler on `SIGTERM` and `SIGINT`. 7. Apply log rotation to the actual cron output file. 8. Document installation and uninstallation procedures for any scheduler. 9. Check existing deployments for duplicate Node.js processes and duplicate crontab entries before upgrading. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (43)

Credential Access

High
Category
Privilege Escalation
Content
### 问题2:API调用失败

**可能原因:**
1. Access Token过期
2. 参数格式错误
3. 权限不足
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 问题2:API调用失败

**可能原因:**
1. Access Token过期
2. 参数格式错误
3. 权限不足
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 问题2:API调用失败

**可能原因:**
1. Access Token过期
2. 参数格式错误
3. 权限不足
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
**解决方案:**
```javascript
// 测试获取Access Token
const wechatAPI = new WeChatWorkAPI(config);
const token = await wechatAPI.getAccessToken(config.wechatWork.corpId, config.wechatWork.corpSecret);
console.log('Access Token:', token);
Confidence
96% confidence
Finding
At this location, the documentation instructs users to retrieve an access token using the application's CorpID and CorpSecret as part of troubleshooting. While obtaining a token is normal, in this context it is immediately paired with printing the token, creating a practical credential exposure path and normalizing unsafe handling of secrets.

Credential Access

High
Category
Privilege Escalation
Content
// 测试获取Access Token
const wechatAPI = new WeChatWorkAPI(config);
const token = await wechatAPI.getAccessToken(config.wechatWork.corpId, config.wechatWork.corpSecret);
console.log('Access Token:', token);
```

### 问题3:智能表格记录失败
Confidence
99% confidence
Finding
This line logs the access token directly to the console, exposing a valid credential that can be reused by anyone with access to logs or terminal output. Because access tokens are bearer tokens, disclosure can enable unauthorized API calls until the token expires, and such output may be retained in CI/CD or support logs beyond the token lifetime as evidence of poor secret handling.

Known Vulnerable Dependency: axios==1.13.6 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
97% confidence
Finding
axios is a runtime dependency of this collector skill, so known SSRF, proxy bypass, redirect, or prototype-pollution-related flaws can directly affect network-facing behavior. In a scraping/collector context that fetches remote content, this increases risk because attacker-influenced URLs, redirects, or proxy environment handling may allow internal network access, credential leakage, or response tampering.

Known Vulnerable Dependency: basic-ftp==5.2.0 — 4 advisory(ies): GHSA-6v7q-wjvx-w8wg (basic-ftp: Incomplete CRLF Injection Protection Allows Arbitrary FTP Command Exe); CVE-2026-39983 (basic-ftp has FTP Command Injection via CRLF); CVE-2026-41324 (basic-ftp vulnerable to denial of service via unbounded memory consumption in Cl) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: brace-expansion==1.1.12 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: browserslist==4.28.1 — 2 advisory(ies): CVE-2026-73088 (Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.); CVE-2026-73089 (Browserslist: Unbounded memory growth (no cache eviction) via distinct query res)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: js-yaml==4.1.1 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: extract-zip==2.0.1 — 2 advisory(ies): CVE-2026-19693 (extract-zip allows arbitrary file writes through symlink archive entries); CVE-2026-56876 (extract-zip unvalidated symlink path traversal)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
90% confidence
Finding
form-data is a runtime dependency of axios and the cited CRLF injection issue can become dangerous if attacker-controlled field names or filenames are used when building multipart requests. In a data-collection agent, this could enable request smuggling or header/body manipulation toward downstream services if multipart uploads are implemented.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Credential Access

High
Category
Privilege Escalation
Content
console.log('\n⚠️  智能表格ID未配置,跳过表格测试');
    }
    
    // 测试4: 获取Access Token(如果配置了CorpID和Secret)
    if (wechatConfig.corpId && wechatConfig.corpSecret) {
      console.log('\n🔑 测试4: 获取Access Token...');
      const token = await wechatAPI.getAccessToken(wechatConfig.corpId, wechatConfig.corpSecret);
Confidence
82% confidence
Finding
The code retrieves an enterprise WeChat access token using configured credentials as part of a test flow. In context this is expected functionality, but handling live credentials and tokens in a test script increases exposure risk, especially if the script is run in shared environments or with verbose logging.

Credential Access

High
Category
Privilege Escalation
Content
// 测试4: 获取Access Token(如果配置了CorpID和Secret)
    if (wechatConfig.corpId && wechatConfig.corpSecret) {
      console.log('\n🔑 测试4: 获取Access Token...');
      const token = await wechatAPI.getAccessToken(wechatConfig.corpId, wechatConfig.corpSecret);
      console.log(`✅ Access Token获取成功: ${token.substring(0, 20)}...`);
    } else {
Confidence
97% confidence
Finding
The script logs the first 20 characters of the access token to stdout after successful retrieval. Even partial credential disclosure can aid token identification, correlation across logs, or accidental leakage through CI logs, terminals, or centralized log platforms.

Missing User Warnings

High
Confidence
98% confidence
Finding
These lines directly print highly sensitive configuration values including the callback token and EncodingAESKey. Exposure of these values can enable unauthorized parties to forge or interfere with WeCom message validation and compromises secrecy well beyond simple misconfiguration troubleshooting.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README explicitly describes automatically recording collected bidding information into WeCom smart tables, but it does not warn users that data will be transmitted to an external enterprise service or that automated writes will occur. In an agent skill context, this can lead to unintended exfiltration of collected data, accidental disclosure of procurement-related information, or unauthorized modification of shared business records if users deploy it without understanding the integration.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill explicitly describes automatic collection and population of externally sourced procurement data into a WeChat Work smart table on a daily schedule, but provides no warning, approval gate, or validation controls around outbound transmission and record modification. This creates a real risk of silently sending scraped data to an external business system and overwriting or polluting records with inaccurate, manipulated, or sensitive information.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The troubleshooting example explicitly prints an access token to the console, which can expose a live bearer credential through terminal history, CI logs, shared screenshots, or centralized logging systems. Even in documentation, this pattern encourages unsafe operator behavior and can lead to unauthorized API use if the token is captured.

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The code path for recording bidding information does more than the surrounding comment suggests: postToWeChatWork sends a proactive Markdown message to WeChat Work and may also write to a smart table. This creates a transparency and data-minimization issue because collected procurement details are automatically broadcast to an external collaboration platform, which can surprise operators and leak business-sensitive information more broadly than intended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The workflow automatically transmits collected bidding data to WeChat Work during scheduled and immediate execution without any approval gate, preview, or explicit warning. In this skill context, the data concerns procurement opportunities and internal sales assignment, so unintended transmission can expose commercially sensitive information, cause compliance issues, or notify the wrong audience at scale.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The script is described as a configuration validator, but it reads a local config file and later prints secret values such as the WeCom token and EncodingAESKey to stdout. This creates an information-disclosure risk because terminal output may be captured in logs, CI pipelines, shell history, or shared support screenshots.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
All user-facing descriptions and console messages in the file are hard-coded in Chinese, which imposes a specific language on users without opt-in or explanation. Under the language/locale policy, this is a natural-language locale constraint that should either be optional or clearly justified as region-specific.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The method is documented as decrypting callback messages, but it only logs and returns the encrypted input unchanged. This can cause downstream code to treat undeciphered data as trusted callback content, breaking security assumptions and potentially leading to incorrect processing, audit gaps, or accidental exposure of sensitive encrypted payloads in logs.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code logs callback message contents directly with console.log, even though callback payloads may contain sensitive business data or identifiers. In an agent/integration context, logs are often centralized and broadly accessible, so this increases the risk of unintended disclosure without any sanitization or warning.

Static analysis

No suspicious patterns detected.