T09 · Insecure Skill Coding Practices
- Location
scripts/fetch_bili_user_works.py:75- Finding
Unvalidated API-Controlled URLs Rendered as Clickable Links
- Content
View full analysis
Vulnerability Details
File Location:
scripts/fetch_bili_user_works.py:75-82
Related Sink:references/core_workflow.md:87
Vulnerability Type: Improper validation of externally controlled URLs
Risk Level: MediumVulnerable Code
python def build_video_url(item: dict) -> str: """优先使用 url 字段;若为空则用 bvId 拼接标准 B站链接""" url = item.get("url") or "" if url: return url bv_id = item.get("bvId") or "" if bv_id: return f"https://www.bilibili.com/video/{bv_id}" return ""The workflow subsequently requires
work_urlto be rendered directly as a Markdown link:markdown **标题规则:** `[标题](work_url)`;超过 30 字截断并加 `...`Technical Analysis
The
urlvalue originates from the external RedFox API response.build_video_url()accepts that value without parsing it, enforcing HTTPS, or restricting it to trusted Bilibili domains. The returned value becomeswork_url, which the workflow directs the agent to place into a clickable Markdown link.Consequently, trust placed in the Skill's output extends to an arbitrary URL selected by the remote API. If the API service, upstream data source, transport endpoint, or relevant response-generation component is compromised, an attacker can inject a phishing or tracking URL. Client behavior may also make non-HTTP schemes hazardous.
The safe fallback based on
bvIddoes not mitigate this issue because it is only used when the API-providedurlis empty.Attack Path
- An attacker gains the ability to influence a RedFox API response, such as through compromise of the service or poisoning of its upstream data.
- The attacker places an arbitrary URL in an item's
urlfield. - The script receives the response and passes the URL through
build_video_url()unchanged. - The URL is returned in the JSON output as
work_url. - Following the documented workflow, the agent embeds
work_urlinto a clickable video-title link. - A user trusts the agent-gene ...[truncated 756 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse every API-provided URL with
urllib.parse.urlparse. - Require the scheme to be exactly
https. - Allowlist expected Bilibili hosts, such as
www.bilibili.com, and reject deceptive suffix or user-information forms. - Prefer constructing canonical URLs locally from a validated
bvIdrather than trusting the API's complete URL. - Validate
bvIdagainst the expected identifier format before interpolation. - If neither a trusted URL nor a valid identifier is available, return an empty URL and render the title as plain text.
- Apply equivalent validation to other externally supplied URLs, including cover and avatar URLs, before displaying or fetching them.
- Add tests for malicious inputs such as
javascript:schemes, HTTP URLs, unrelated domains, user-information host confusion, and malformed identifiers.
A hardened implementation should follow this pattern:
python import re from urllib.parse import urlparse TRUSTED_VIDEO_HOSTS = {"www.bilibili.com"} BV_ID_RE = re.compile(r"^BV[0-9A-Za-z]+$") def build_video_url(item: dict) -> str: url = str(item.get("url") or "").strip() if url: parsed = urlparse(url) if ( parsed.scheme == "https" and parsed.hostname in TRUSTED_VIDEO_HOSTS and parsed.username is None and parsed.password is None ): return url bv_id = str(item.get("bvId") or "").strip() if BV_ID_RE.fullmatch(bv_id): return f"https://www.bilibili.com/video/{bv_id}" return ""- Parse every API-provided URL with
