Back to skill

Security audit

小程序变现助手

Security checks for vulnerabilities and agentic risk

Overview

This Chinese mini-program monetization guide is not deceptive, but its payment and membership examples contain serious security gaps that could mishandle paid access or revenue.

Install only if you treat this as a high-level monetization reference, not production-ready payment code. Before using its examples, require server-authoritative pricing, verified payment callbacks, order locking, amount and currency reconciliation, idempotent fulfillment, authenticated user identity, pinned dependencies, and a review by someone familiar with WeChat Pay security.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
references/wechat-pay-guide.md:220
Finding
Client-Controlled Payment Amount Enables Order Price Manipulation<![CDATA[ ## Vulnerability Details **File Location**: `references/wechat-pay-guide.md`, lines 220–229 **Vulnerability Type**: Client-side price manipulation **Risk Level**: High ### Vulnerable Code ```javascript const res = await wx.request({ url: 'https://yourdomain.com/api/orders', method: 'POST', data: { productId: this.data.productId, amount: this.data.amount } }) return res.data ``` ### Technical Analysis The order request sends both the product identifier and payment amount from the mini-program client. Client-side state such as `this.data.amount` cannot be trusted because users can modify the application, intercept requests, or directly invoke the API with an arbitrary payload. The guide does not instruct the server to disregard the submitted amount and retrieve the authoritative price from a trusted product or membership-plan record. If the backend uses this value when creating the local order or WeChat transaction, the user controls the amount charged. ### Attack Path 1. An attacker selects a legitimate paid product. 2. The attacker intercepts or reproduces the request to `/api/orders`. 3. The attacker retains the legitimate `productId` but replaces `amount` with a reduced value, such as one cent. 4. The backend creates an underpriced order using the client-provided amount. 5. The attacker completes the valid WeChat payment for the reduced amount. 6. The application treats the product order as paid and grants the associated goods or service. ### Impact Assessment Successful exploitation can allow an unauthenticated or ordinary authenticated customer to purchase products or memberships below their configured price. The affected scope includes payment integrity, order revenue, product fulfillment, membership access, and financial reconciliation. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Do not accept an authoritative price or payment amount from the client. - Require the client to submit only a product or plan identifier and any permitted quantity. - On the server, retrieve the active product record and calculate the amount from trusted database values. - Persist the expected amount and currency in the order before creating the WeChat transaction. - Reject inactive products, invalid quantities, and prices outside supported integer-cent ranges. - During the payment callback, compare the paid amount and currency against the persisted order. - Add integration tests that submit modified, negative, zero, excessive, and stale prices. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/wechat-pay-guide.md:121
Finding
Payment Callback Marks Orders Paid Without Complete Transaction Reconciliation<![CDATA[ ## Vulnerability Details **File Location**: `references/wechat-pay-guide.md`, lines 121–138 **Vulnerability Type**: Incomplete payment callback validation **Risk Level**: High ### Vulnerable Code ```javascript // 2. 解密数据 const data = pay.decipher(req.body.resource) // 3. 更新订单状态 const { out_trade_no, transaction_id } = data await db.query(` UPDATE orders SET status = 'paid', transaction_id = ?, paid_at = NOW() WHERE order_id = ? `, [transaction_id, out_trade_no]) // 4. 返回成功 res.json({ code: 'SUCCESS', message: '成功' }) ``` The preceding example verifies the callback signature, but the order update above performs no further reconciliation of the decrypted transaction. ### Technical Analysis A valid signature establishes that the notification was signed by the payment platform, but it does not establish that every field in the notification matches the local order being fulfilled. The implementation marks an order paid based only on `out_trade_no`. It does not validate: - Successful transaction state - Merchant identifier - Application identifier - Paid amount and currency - Whether the order is still pending - Whether the transaction identifier has already been assigned elsewhere - Whether the order has already been fulfilled The update is also not shown as part of a transaction that atomically changes the order from `pending` to `paid`. Although the document later mentions idempotency as general advice, the callback implementation does not enforce it. ### Attack Path 1. A signed payment notification reaches the callback endpoint. 2. The handler verifies the signature and decrypts the resource. 3. The handler extracts only `out_trade_no` and `transaction_id`. 4. The database update marks the matching local order as paid without checking the notification’s merchant, application, amount, currency, or transaction state. 5. Downstream fulfillment logic relies on the altered order status and grants the product or membership. 6. ...[truncated 533 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Lock the local order and process the callback in a database transaction. - Verify the transaction state explicitly indicates successful payment. - Compare the notification’s merchant ID and application ID with configured trusted values. - Compare the paid amount and currency with the immutable values stored on the local order. - Require an atomic transition such as `UPDATE ... WHERE order_id = ? AND status = 'pending'`. - Add a uniqueness constraint for the platform transaction identifier. - Record a separate one-time fulfillment state and make fulfillment idempotent. - Return success for legitimate duplicate callbacks only after confirming that the stored transaction matches. - Retain an auditable record of callback identifiers and validation outcomes without logging payment secrets. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/membership-implementation.md:115
Finding
Membership Activation and Renewal Do Not Require Verified Payment<![CDATA[ ## Vulnerability Details **File Locations**: - `references/membership-implementation.md`, lines 115–174 - `references/membership-implementation.md`, lines 455–458 **Vulnerability Type**: Payment authorization bypass **Risk Level**: Critical ### Vulnerable Code The membership service accepts an order identifier and directly creates an active membership: ```javascript async subscribe(userId, planId, orderId) { const connection = await db.getConnection() try { await connection.beginTransaction() // 1. 获取套餐信息 const [plan] = await connection.query( 'SELECT * FROM membership_plans WHERE id = ? AND is_active = true', [planId] ) if (!plan) { throw new Error('套餐不存在或已下架') } // 2. 检查是否有现有会员 const [existing] = await connection.query(` SELECT * FROM memberships WHERE user_id = ? AND status = 'active' FOR UPDATE `, [userId]) // 3. 计算会员时间 let startTime = new Date() let endTime = new Date() if (existing) { // 有现有会员,从现有结束时间开始续期 startTime = new Date(existing.end_time) endTime = new Date(startTime) endTime.setDate(endTime.getDate() + plan.duration_days) // 升级套餐 if (plan.duration_days > existing.plan_duration) { await connection.query(` UPDATE memberships SET status = 'cancelled' WHERE id = ? `, [existing.id]) } } else { endTime.setDate(endTime.getDate() + plan.duration_days) } // 4. 创建会员记录 const [result] = await connection.query(` INSERT INTO memberships (user_id, plan_id, order_id, start_time, end_time) VALUES (?, ?, ?, ?, ?) `, [userId, planId, orderId, startTime, endTime]) // 5. 记录日志 await connection.query(` INSERT INTO subscription_logs (user_id, action, plan_id, amount) VALUES (?, 'subscribe', ?, ?) `, [userId, planId, plan.price]) await connection.commit() return { ...[truncated 2407 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Make membership activation an internal operation that cannot be directly invoked by an untrusted client. - Trigger activation only after the server has verified and reconciled a successful payment callback. - In one database transaction: 1. Lock the order. 2. Confirm that it belongs to the authenticated user. 3. Confirm that its product type and plan match the requested membership. 4. Confirm that its paid amount and currency match authoritative server-side pricing. 5. Confirm that it has not already been fulfilled. 6. Mark it fulfilled and create or extend the membership. - Add a unique constraint to prevent the same order from creating multiple memberships. - Derive `userId` from the authenticated server session rather than a request parameter. - Do not implement renewal by generating an order ID alone. Create a real renewal order and extend the membership only after successful settlement. - Where automatic renewal is supported, use an authorized recurring-payment mechanism and retain consent and transaction records. - Add tests for unpaid, cancelled, mismatched, replayed, cross-user, and underpaid orders. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/ad-monetization.md:254
Finding
Client-Controlled User Identifier Is Used for Advertisement Entitlement<![CDATA[ ## Vulnerability Details **File Location**: `references/ad-monetization.md`, lines 254–268 **Vulnerability Type**: Client-side authorization decision **Risk Level**: Medium ### Vulnerable Code ```javascript // 判断是否显示广告 async function shouldShowAd(userId) { const membership = await checkMembership(userId) return !membership.isMember } // 页面中 Page({ data: { showAd: true }, async onLoad() { const showAd = await shouldShowAd(wx.getStorageSync('userId')) this.setData({ showAd }) } }) ``` ### Technical Analysis The entitlement decision is based on a `userId` retrieved from client-side storage. Local storage is controlled by the user and cannot serve as a trusted identity or authorization source. An attacker can replace the stored identifier with another user’s identifier. If `checkMembership()` accepts that value without binding it to an authenticated server session, the application performs the membership check for the selected account rather than the current user. The immediate example controls advertisement removal, but the same design becomes more severe if reused for premium functionality or user-specific data. ### Attack Path 1. The attacker modifies the mini-program’s local `userId` value. 2. The attacker substitutes the identifier of an account with an active membership. 3. `onLoad()` passes the modified identifier to `shouldShowAd()`. 4. `checkMembership()` returns the target account’s active membership status. 5. `showAd` is set to false and advertisements are suppressed for the attacker. ### Impact Assessment The demonstrated impact is unauthorized advertisement removal and loss of advertising revenue. If the same identity pattern is reused by membership APIs, the scope could include unauthorized premium features or access to another user’s membership-related information. The code shown does not itself establish access to broader account data. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Never use a client-provided or locally stored user ID as the authoritative identity for an entitlement check. - Authenticate requests using a server-managed session or validated WeChat login credential. - Resolve the internal user ID on the server from the authenticated session or OpenID mapping. - Return the current user’s advertisement entitlement from an authenticated endpoint. - Enforce premium authorization on the server for every protected operation, even if the client hides or shows interface elements. - Use local storage only as a non-authoritative display cache and handle it as attacker-controlled input. - Add authorization tests that attempt to submit another user’s identifier. ]]>

T08 · Insecure Dependencies

Warning
Location
references/wechat-pay-guide.md:45
Finding
Third-Party Payment Dependencies Are Installed Without Version Pinning<![CDATA[ ## Vulnerability Details **File Location**: `references/wechat-pay-guide.md`, line 45 **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash npm install wechatpay-node-v3 axios ``` ### Technical Analysis The installation command does not specify reviewed versions. It therefore resolves mutable package versions according to registry state at installation time. The guide also does not require a committed lockfile, integrity verification, lifecycle-script review, or package provenance checks. Because these dependencies are intended for a payment backend, installed package code may execute with access to merchant configuration, payment certificates, API keys, network access, and application data. This finding identifies unsafe dependency management; the audit did not establish that the named packages are themselves malicious. ### Attack Path 1. A developer follows the documented installation command. 2. npm resolves the packages and transitive dependencies available at that time. 3. A compromised registry account, malicious future release, or compromised transitive dependency supplies altered code. 4. Package lifecycle scripts may execute during installation, or malicious code executes when imported at runtime. 5. The compromised dependency operates in the payment backend’s security context and may access credentials or transaction data. ### Impact Assessment A successful supply-chain compromise could affect the full payment service process. Potential consequences include merchant-key theft, payment-data exposure, arbitrary code execution under the service account, outbound data transmission, or manipulation of payment operations. The actual impact depends on the permissions and secrets available to the installation and runtime environment. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Verify package names and provenance through official WeChat documentation and trusted registries. - Pin exact, reviewed dependency versions rather than installing mutable latest releases. - Commit the generated lockfile and use `npm ci` in reproducible build environments. - Enforce lockfile integrity and prevent unreviewed dependency changes in continuous integration. - Review install and lifecycle scripts; consider disabling scripts during installation where operationally possible. - Scan direct and transitive dependencies for known vulnerabilities and suspicious ownership changes. - Run the payment service with least privilege and isolate payment certificates and API keys. - Establish a controlled update process that reviews and tests new dependency versions before deployment. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (9)

Hidden Instructions

High
Category
Prompt Injection
Content
**代码实现:**

```xml
<!-- 页面底部Banner广告 -->
<ad unit-id="adunit-xxx" ad-type="banner" />
```
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**代码实现:**

```xml
<!-- 页面底部Banner广告 -->
<ad unit-id="adunit-xxx" ad-type="banner" />
```
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The natural-language content presents the skill in Chinese and does not indicate that the user can choose another language. Under the policy, forcing a specific language without user opt-in is a language/locale policy concern unless the restriction is clearly justified.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The skill says to use it when users mention broad terms like "会员系统", "支付接入", and similar keywords, which can appear in many general product or development conversations beyond monetization-specific requests. It does not provide exclusion conditions or negative examples to clarify when those terms should not invoke this skill.

External Transmission

Medium
Category
Data Exfiltration
Content
```

**后端关键点:**
- 统一下单接口:`https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi`
- 签名算法:HMAC-SHA256
- 回调通知:验签 + 更新订单状态
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```

**后端关键点:**
- 统一下单接口:`https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi`
- 签名算法:HMAC-SHA256
- 回调通知:验签 + 更新订单状态
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
In this markdown file, the embedded frontend purchase flow creates an order, requests payment parameters, and triggers payment via multiple remote API calls, but the surrounding skill description provides no warning that user/order data will be sent to backend payment endpoints or that a paid action will be initiated. Under the markdown criteria for SQP-2, behaviors affecting user data and financial actions should be disclosed clearly in the description.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The file’s natural-language instructions, examples, and labels are all presented only in Chinese. Under the policy rule, forcing a specific language without user opt-in can be a locale/language policy violation when no alternative or justification is provided.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
该技能文档从标题开始即完全以中文编写,没有说明这是面向特定中文用户群体的区域性文档,也没有提供其他语言选项或用户可选的本地化说明。根据规则,强制单一语言而无用户选择,属于自然语言层面的语言/locale 政策风险。

Static analysis

No suspicious patterns detected.