T09 · Insecure Skill Coding Practices
- Location
scripts/dispatch_morning_greeting.py:107- Finding
Unrestricted webhook destination permits SSRF and unintended message disclosure
- Content
View full analysis
Vulnerability Details
File Location:
scripts/dispatch_morning_greeting.py:107-110, 140-148, 195-211, 238-253, 323-333
Vulnerability Type: Server-Side Request Forgery through insufficient webhook validation
Risk Level: MediumVulnerable Code
python def build_weixin_webhook_from_key(key): normalized = normalize_text(key) if not normalized: return None if normalized.startswith(("http://", "https://")): return normalized encoded = urllib.parse.quote(normalized, safe="") return f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={encoded}"python def looks_like_webhook_url(value): normalized = normalize_text(value) if not normalized: return False return normalized.startswith(("http://", "https://"))python def detect_weixin_from_env(): for key in WEIXIN_ENV_WEBHOOKS: value = normalize_text(os.environ.get(key)) if value: webhook = build_weixin_webhook_from_key(value) if webhook: return { "source": f"env:{key}", "webhook_url": webhook, } for key in WEIXIN_ENV_KEYS: value = normalize_text(os.environ.get(key)) if value: webhook = build_weixin_webhook_from_key(value) if webhook: return { "source": f"env:{key}", "webhook_url": webhook, } return Nonepython if normalized_value: if is_weixin_webhook_url(normalized_value): return build_weixin_webhook_from_key(normalized_value) if normalized_key in LIKELY_WEBHOOK_FIELDS: if "webhook" in normalized_key and looks_like_weixin_key(normalized_value): return build_weixin_webhook_from_key(normalized_value) if normalized_key in LIKELY_KEY_FIELDS and looks_l ...[truncated 4312 chars]- Remediation
View remediation
Remediation Suggestions
-
Enforce an exact destination allowlist immediately before sending:
- Require the
httpsscheme. - Require the exact hostname
qyapi.weixin.qq.com. - Require the exact path
/cgi-bin/webhook/send. - Reject user information, fragments, non-default ports, and unexpected query parameters.
- Require exactly one valid
keyparameter.
- Require the
-
Do not accept complete URLs from variables intended to contain webhook keys. Treat key variables strictly as opaque keys and construct the official URL internally.
-
If full webhook URL variables must remain supported, validate them with a dedicated function and reject all non-Weixin hosts rather than merely checking for an HTTP or HTTPS prefix.
-
Disable redirects or validate every redirect destination against the same allowlist. A validated initial URL must not be allowed to redirect to an internal or unapproved host.
-
Resolve the destination and reject loopback, private, link-local, multicast, reserved, and metadata-service addresses. Repeat validation after DNS resolution and for every redirect to reduce DNS rebinding risk.
-
Remove generic
urlfromLIKELY_WEBHOOK_FIELDS, or only inspect explicit webhook fields within a narrowly defined Weixin bot configuration schema. Avoid recursive interpretation of loosely related configuration values. -
Reject cleartext HTTP entirely to protect webhook keys and message content in transit.
-
Add tests covering attacker-controlled public hosts, loopback addresses, private network ranges, IPv6 local addresses, encoded hostnames, user-information syntax, nonstandard ports, redirects, and malformed or duplicate
keyparameters.
-
