T09 · Insecure Skill Coding Practices
- Location
mch-demo/server.py:95- Finding
Fail-Open Mock Mode Allows Payment and Callback Verification Bypass
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent paid cloud health-record service, but its included server has payment-bypass, replay, and sensitive-data retention weaknesses that warrant Review before install.
Review before installing or deploying. Use only if you are comfortable sending child health information to the merchant cloud service and using the WeChat payment flow. Before production use, disable fail-open mock behavior, require complete credentials, bind orders to request/session state, add expiration and deletion for health records, enforce request size/rate limits, pin dependencies, and protect payment keys with a proper secrets mechanism.
mch-demo/server.py:95Fail-Open Mock Mode Allows Payment and Callback Verification Bypass
mch-demo/server.py:654Paid Order Numbers Are Replayable and Not Bound to Request Content
mch-demo/server.py:691Sensitive Pediatric Health Records Are Retained Without Expiration
mch-demo/server.py:637Unbounded Request Body Reading Enables Remote Resource Exhaustion
mch-demo/requirements.txt:1Production Dependencies Are Unpinned and Lack Integrity Verification
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"Content-Type": "application/json",
"Accept": "application/json",
}
r = requests.post(WX_BASE + path, data=body.encode(), headers=headers, timeout=20)
r.raise_for_status()
return r.json().get("code_url", "")
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"Authorization": _wx_authorization("GET", path, ""),
"Accept": "application/json",
}
r = requests.get(WX_BASE + path, headers=headers, timeout=20)
r.raise_for_status()
return r.json().get("trade_state", "")
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"Authorization": _wx_authorization("GET", path, ""),
"Accept": "application/json",
}
r = requests.get(WX_BASE + path, headers=headers, timeout=20)
r.raise_for_status()
return r.json().get("trade_state", "")
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
sign_str = f"POST\n{PREORDER_PATH}\n{ts}\n{nonce}\n{payment_required}\n"
l1["signature"] = _sign(_load_sh_key(), sign_str)
headers = {"Content-Type": "application/json", "Accept": "application/json"}
r = requests.post(PREORDER_URL, data=json.dumps(l1).encode(), headers=headers, timeout=20)
r.raise_for_status()
data = r.json()
# 优先取接口返回的 payment_code;否则用本机生成的 L1 信封
The declared purpose says data is submitted to mch.1001058.xyz for one-time record generation, but the behavior described/observed includes broader payment orchestration, third-party payment communications, callback handling, and transient state retention that are not fully disclosed. This is dangerous because users and agents may consent to a narrow pediatric-record service while the skill actually triggers additional processing paths involving child health data, payments, and extra external systems, creating material privacy, transparency, and compliance risk.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制本文件为 .env 并填入真实值(不要提交 .env 到 git)
# ===== 微信支付侧(商户平台获取)=====
MCH_ID=1900000001
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制本文件为 .env 并填入真实值(不要提交 .env 到 git)
# ===== 微信支付侧(商户平台获取)=====
MCH_ID=1900000001
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制本文件为 .env 并填入真实值(不要提交 .env 到 git)
# ===== 微信支付侧(商户平台获取)=====
MCH_ID=1900000001
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制服务代码
COPY server.py .
# 不把 .env 打进镜像;运行时通过挂载或环境变量注入
# 如需默认值,可改为 COPY .env.example .env.example
EXPOSE 8080
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制服务代码
COPY server.py .
# 不把 .env 打进镜像;运行时通过挂载或环境变量注入
# 如需默认值,可改为 COPY .env.example .env.example
EXPOSE 8080
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制服务代码
COPY server.py .
# 不把 .env 打进镜像;运行时通过挂载或环境变量注入
# 如需默认值,可改为 COPY .env.example .env.example
EXPOSE 8080
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制服务代码
COPY server.py .
# 不把 .env 打进镜像;运行时通过挂载或环境变量注入
# 如需默认值,可改为 COPY .env.example .env.example
EXPOSE 8080
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制服务代码
COPY server.py .
# 不把 .env 打进镜像;运行时通过挂载或环境变量注入
# 如需默认值,可改为 COPY .env.example .env.example
EXPOSE 8080
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 复制服务代码
COPY server.py .
# 不把 .env 打进镜像;运行时通过挂载或环境变量注入
# 如需默认值,可改为 COPY .env.example .env.example
EXPOSE 8080
Loading a local .env file into the container commonly injects secrets such as API keys, payment credentials, or private configuration at runtime. In a skill handling pediatric health records and payment-related materials, this increases the sensitivity of any accidental exposure through image leakage, misconfigured logging, debugging endpoints, or compromised container access.
container_name: mch-demo
restart: unless-stopped
env_file:
- .env
ports:
- "8080:8080"
volumes:
This compose file mounts a WeChat Pay private key from the host into the container, exposing a highly sensitive signing credential to the application runtime. If the container is compromised, an attacker could steal the key and impersonate the merchant or sign fraudulent payment-related requests, and the hardcoded host path also reveals local filesystem details.
ports:
- "8080:8080"
volumes:
# 把微信支付私钥挂进容器,路径与 .env 的 PRIVATE_KEY_PATH 一致
- "./apiclient_key.pem:/Users/weiwu/cert/1749040075_20260805_cert/apiclient_key.pem:ro"
# SkillHub 开发者私钥(PEM),对应 .env 的 SKILLHUB_PRIVATE_KEY_FILE
- "./skillhub_private_key.pem:/app/skillhub_private_key.pem:ro"
The SkillHub developer private key is mounted into the application container, making a private signing or authentication credential available to any process that gains access inside the container. Because this service processes sensitive child health data, theft of this key could enable unauthorized requests, impersonation, or abuse of trusted integrations around the skill.
volumes:
# 把微信支付私钥挂进容器,路径与 .env 的 PRIVATE_KEY_PATH 一致
- "./apiclient_key.pem:/Users/weiwu/cert/1749040075_20260805_cert/apiclient_key.pem:ro"
# SkillHub 开发者私钥(PEM),对应 .env 的 SKILLHUB_PRIVATE_KEY_FILE
- "./skillhub_private_key.pem:/app/skillhub_private_key.pem:ro"
# 微信支付公钥(公钥模式验签用),对应 .env 的 WX_PUB_KEY_FILE / WX_PUB_KEY_ID
- "./wechat_pub_key.pem:/app/wechat_pub_key.pem:ro"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
from cryptography.x509 import load_pem_x509_certificate
def _load_dotenv(path=".env"):
"""健壮加载 .env,支持无引号多行 PEM 私钥(如 SkillHub 私钥)。
原生 python-dotenv 对无引号多行值解析失败,这里手动处理:
遇到 KEY= 且值以 -----BEGIN 开头、不含 -----END 时进入多行收集,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
from cryptography.x509 import load_pem_x509_certificate
def _load_dotenv(path=".env"):
"""健壮加载 .env,支持无引号多行 PEM 私钥(如 SkillHub 私钥)。
原生 python-dotenv 对无引号多行值解析失败,这里手动处理:
遇到 KEY= 且值以 -----BEGIN 开头、不含 -----END 时进入多行收集,
The deployment flow relies on editing a plaintext .env file on the NAS to supply operational configuration tied to payment processing, in a project that also stores merchant secrets. In practice this encourages secret handling through files that may be exposed via weak permissions, backups, shell history, or accidental sharing, creating a realistic path to credential theft and fraudulent payment operations.
443 → NAS 的 LAN IP 44380 → NAS 的 LAN IP 80(仅 Let's Encrypt HTTP-01 验证时需要,验证完可关,但建议常开以免证书续期失败)在 NAS 上把 mch-demo/.env 里的占位改成真实公网地址,然后重启容器(Container Manager → 项目 → 重新部署 / 容器 → 重启):
PAY_NOTIFY_URL=https://<你的域名>/api/pay/notify
This section states that apiclient_key.pem is mounted into the container and that paths align with values in .env, confirming that sensitive merchant key material is deployed as filesystem artifacts on the NAS/container stack. Private key exposure would let an attacker impersonate the merchant to payment APIs or abuse callback-related trust, which is especially serious for a public-facing payment service tied to pediatric health data workflows.
## 你的实际方案:Cloudflare Tunnel(已打通,采用此方式)
- **不需要**路由器开 80/443,也**不需要**群晖自己签证书。Cloudflare 在边缘终止 TLS,NAS 上只把容器 8080 暴露给本机 `localhost` 即可。
- 容器已在 NAS 跑起来并发布 `8080` 到本机(docker-compose 已加 `apiclient_key.pem` 挂载,证书路径与 .env 一致)。
- 在 **Cloudflare Zero Trust → Access → Tunnels → 你的 tunnel → Public Hostname** 添加一条:
- Subdomain:`mch` Domain:`1001058.xyz` Type:`HTTP` URL:`http://localhost:8080`
- (子域名随意,只要和 `.env` 的 `PAY_NOTIFY_URL` 对应;当前已设为 `https://mch.1001058.xyz`)
The skill declares network- and environment-dependent behavior but omits any explicit tool/permission scope, which weakens platform-level consent and policy enforcement. In this context the skill handles highly sensitive children's health data and payment-related flows, so undeclared capabilities increase the risk of unauthorized exfiltration, accidental overreach, or unsafe execution by an agent runtime.
The skill’s natural-language instructions and user-facing example copy are entirely in Chinese, and the document does not indicate that users may choose another language or locale. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly documented and justified.
The skill loads a broad set of payment, certificate, and private-key materials from environment variables, which exceeds the minimum capability implied by a pediatric-record organization skill. In a health-data context, unnecessary secret-handling capability raises the consequences of compromise and broadens the blast radius if the service is abused or misconfigured.
The implementation behaves as a generic WeChat/SkillHub payment merchant demo rather than a narrowly scoped pediatric-record submission service tied to the manifest-declared merchant endpoint mch.1001058.xyz. This scope mismatch increases the attack surface and makes it easier to process payments, callbacks, and related data flows beyond what users would reasonably expect from the stated health-record service.
No suspicious patterns detected.