Back to skill

Security audit

多源音乐下载

Security checks for vulnerabilities and agentic risk

Overview

This music downloader does what it says, but it disables HTTPS certificate checks broadly and downloads remote-provided files without enough validation or size limits.

Install only if you are comfortable with a downloader that contacts many third-party music sites, bypasses HTTPS certificate validation, and saves remote content to /tmp/music. Prefer a fixed version that keeps TLS verification enabled, validates media URL domains and file types, and enforces a reasonable maximum download size.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
music_downloader.py:15
Finding
TLS Certificate Verification Is Disabled for All Network Requests<![CDATA[ ## Vulnerability Details **File Location**: `music_downloader.py:15, 34-37, 63-65, 73-75, 91-93, 101-103, 119-121, 129-131, 149-151, 156-158, 166-168, 187-189, 194-196, 208-210, 221-223, 230-232, 244-246, 256-258, 269-271, 280-282, 296-298, 311-313, 324-326, 378-380` **Vulnerability Type**: Improper TLS certificate validation **Risk Level**: High ### Vulnerable Code The code globally suppresses warnings and explicitly disables certificate verification throughout the search, API, URL-resolution, and download workflows: ```python warnings.filterwarnings('ignore') ``` Representative search request: ```python def search_thttt(self, keyword: str) -> List[Dict]: try: url = f"https://www.thttt.com/so.php?wd={quote(keyword)}" resp = self.session.get(url, timeout=15, verify=False) html = resp.text ``` Representative API request: ```python def get_url_thttt(self, hash_code: str) -> Optional[str]: try: url = "https://www.thttt.com/style/js/play.php" resp = self.session.post( url, data={'id': hash_code, 'type': 'dance'}, timeout=15, verify=False ) result = resp.json() ``` The final media download also disables certificate verification: ```python try: resp = self.session.get( url, headers=headers, timeout=60, stream=True, verify=False ) resp.raise_for_status() ``` The same `verify=False` setting appears in every provider integration at lines 37, 65, 75, 93, 103, 121, 131, 151, 158, 168, 189, 196, 210, 223, 232, 246, 258, 271, 282, 298, 313, 326, and 380. ### Technical Analysis The `verify=False` argument instructs Requests not to authenticate the certificate presented by an HTTPS server. Encryption may still be negotiated, but the client cannot establish that it is communicating with the intended provider rather than an impersonating server. Because verification is disabled during both meta ...[truncated 1720 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `verify=False` from all `self.session.get()` and `self.session.post()` calls. Requests should use its default certificate validation: ```python resp = self.session.get(url, timeout=15) ``` 2. Remove the global warning suppression: ```python warnings.filterwarnings('ignore') ``` If warning filtering is needed for unrelated reasons, suppress only a narrowly identified warning at the smallest possible scope. 3. If a specific provider requires a private certificate authority, configure a dedicated CA bundle only for that provider: ```python resp = self.session.get( url, timeout=15, verify="/path/to/provider-ca-bundle.pem" ) ``` 4. Do not use an unverified connection as a compatibility fallback. Treat certificate failures as provider failures and continue to the next source. 5. Keep the operating system and Python CA trust store current. 6. Add automated tests that use an untrusted test certificate and verify that search, API, and download requests fail securely. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
music_downloader.py:364
Finding
Untrusted Provider URLs Are Downloaded Without Destination Validation or a Maximum Size<![CDATA[ ## Vulnerability Details **File Location**: `music_downloader.py:364-391, 425-432` **Vulnerability Type**: Unrestricted server-side URL request and unbounded file download **Risk Level**: Medium ### Vulnerable Code The download method accepts an arbitrary URL, follows redirects using Requests' default behavior, and writes the response without imposing a maximum byte count: ```python def download(self, url: str, save_path: str) -> bool: """下载文件""" if 'kuwo.cn' in url: referer = 'https://www.kuwo.cn/' elif 'kugou.com' in url: referer = 'https://www.kugou.com/' elif '163.com' in url or '126.net' in url: referer = 'https://music.163.com/' elif 'qq.com' in url: referer = 'https://y.qq.com/' else: referer = 'https://www.thttt.com/' headers = {"User-Agent": HEADERS["User-Agent"], "Referer": referer} try: resp = self.session.get( url, headers=headers, timeout=60, stream=True, verify=False ) resp.raise_for_status() size = int(resp.headers.get('content-length', 0)) if size < 1024: print(f" ⚠️ 文件太小: {size} bytes") return False os.makedirs(os.path.dirname(save_path), exist_ok=True) with open(save_path, 'wb') as f: for chunk in resp.iter_content(8192): if chunk: f.write(chunk) print(f" ✅ 下载成功: {save_path}") return True except Exception as e: print(f" ❌ 下载失败: {e}") return False ``` Playback URLs obtained from remote provider responses are passed directly to that method: ```python play_url = get_url_funcs[source](song) if not play_url: print(" ⚠️ 无法获取链接") continue safe_name = re.sub(r'[<>:"/\\|?*]', '_', f"{song['artist']}_{song['name']}") save_path = os.path.join(save_dir, f"{safe_name}.mp3") if self.download(play_url, save_path): return save_p ...[truncated 3018 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only HTTPS playback URLs: ```python from urllib.parse import urlparse parsed = urlparse(url) if parsed.scheme != "https": raise ValueError("Only HTTPS media URLs are allowed") ``` 2. Maintain a strict hostname allowlist for each provider's documented media and CDN domains. Use exact hostname or properly bounded subdomain comparisons rather than substring checks such as `'kuwo.cn' in url`. 3. Resolve the destination and reject loopback, private, link-local, multicast, reserved, and unspecified addresses using Python's `ipaddress` module. Repeat this check for all resolved addresses to reduce DNS rebinding risk. 4. Disable automatic redirects and validate each redirect target before following it: ```python resp = self.session.get( url, headers=headers, timeout=(10, 60), stream=True, allow_redirects=False ) ``` Follow only a small, fixed number of validated HTTPS redirects. 5. Enforce a maximum download size based on both `Content-Length` and bytes actually received: ```python MAX_DOWNLOAD_BYTES = 50 * 1024 * 1024 declared_size = int(resp.headers.get("content-length", 0)) if declared_size and declared_size > MAX_DOWNLOAD_BYTES: raise ValueError("Media file exceeds maximum size") written = 0 with open(save_path, "xb") as output: for chunk in resp.iter_content(8192): if not chunk: continue written += len(chunk) if written > MAX_DOWNLOAD_BYTES: raise ValueError("Media file exceeds maximum size") output.write(chunk) ``` Delete partial output files when validation or downloading fails. 6. Require an expected audio MIME type and validate file magic bytes rather than relying on the `.mp3` extension. 7. Apply execution-environment egress controls so the Skill cannot contact loopback, private, link-local, metadata, or unrelated external destinations. 8. Use randomized, securely created output files where practical, and avoid over ...[truncated 27 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (27)

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill explicitly downloads MP3 files to `/tmp/music/` but does not clearly warn users up front that it writes files to local storage. In an agent setting, undisclosed filesystem writes can surprise users, consume disk space, and create persistence/privacy issues, especially when the content is fetched from multiple untrusted external sources.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The HTTP headers force `Accept-Language` to `zh-CN,zh;q=0.9`, which imposes a specific locale preference in the skill's behavior. The file does not provide any opt-in, configuration, or documented justification for restricting requests to Chinese language content.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_thttt(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.thttt.com/so.php?wd={quote(keyword)}"
            resp = self.session.get(url, timeout=15, verify=False)
            html = resp.text
            
            songs = []
Confidence
99% confidence
Finding
Disabling TLS certificate verification allows a man-in-the-middle attacker to intercept or modify traffic to the remote music source. In this skill, untrusted network responses are used to discover media URLs, so tampered responses could redirect downloads to malicious infrastructure or manipulate results silently.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_thttt(self, hash_code: str) -> Optional[str]:
        try:
            url = "https://www.thttt.com/style/js/play.php"
            resp = self.session.post(url, data={'id': hash_code, 'type': 'dance'}, timeout=15, verify=False)
            result = resp.json()
            return result.get('url') if result.get('msg') == 1 else None
        except:
Confidence
99% confidence
Finding
This POST request disables TLS verification while retrieving playback metadata from an external source. An attacker positioned on the network could forge the JSON response and supply attacker-controlled media URLs, causing unsafe downloads or user deception.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_kugou(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://complexsearch.kugou.com/v2/search/song?keyword={quote(keyword)}&page=1&pagesize=15"
            resp = self.session.get(url, timeout=15, verify=False)
            data = resp.json()
            songs = []
            for item in data.get('data', {}).get('lists', []):
Confidence
99% confidence
Finding
Certificate validation is disabled for the Kugou search request, making search results vulnerable to interception and tampering. Because these results feed later URL resolution and download decisions, a MITM could influence which resources are fetched.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_kugou(self, hash_code: str) -> Optional[str]:
        try:
            url = f"https://www.kugou.com/yy/html/singer.html?hash={hash_code}"
            resp = self.session.get(url, timeout=15, verify=False)
            match = re.search(r'"play_url":"([^"]+)"', resp.text)
            return match.group(1).replace('\\/', '/') if match else None
        except:
Confidence
99% confidence
Finding
This request extracts a play_url from HTML fetched without TLS verification. A network attacker could inject a forged play_url pointing to malicious or unexpected content, leading the downloader to fetch attacker-chosen files.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_kuwo(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={quote(keyword)}&pn=1&rn=15"
            resp = self.session.get(url, headers={"Referer": "https://www.kuwo.cn"}, timeout=15, verify=False)
            data = resp.json()
            songs = []
            for item in data.get('data', {}).get('list', []):
Confidence
99% confidence
Finding
The Kuwo search API call disables certificate validation, exposing the search flow to MITM tampering. Since the application trusts remote metadata to drive subsequent requests, this weakens the entire download chain.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_kuwo(self, rid: str) -> Optional[str]:
        try:
            url = f"https://www.kuwo.cn/api/v1/www/music/playInfo?mid={rid}&type=music&httpsStatus=1"
            resp = self.session.get(url, timeout=15, verify=False)
            return resp.json().get('data', {}).get('url', '')
        except:
            return None
Confidence
99% confidence
Finding
Playback information is requested over HTTPS with verification disabled, allowing an attacker to alter the returned media URL. In a downloader, this is especially risky because the next step is fetching and writing the referenced content to disk.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
try:
            url = f"https://music.163.com/api/search/get?s={quote(keyword)}&type=1&offset=0&limit=15"
            headers = {"Referer": "https://music.163.com"}
            resp = self.session.get(url, headers=headers, timeout=15, verify=False)
            data = resp.json()
            songs = []
            for item in data.get('result', {}).get('songs', []):
Confidence
99% confidence
Finding
Disabling TLS verification for NetEase search makes the metadata channel untrusted even though HTTPS is used. A MITM attacker could manipulate search results and steer the tool toward malicious or unrelated content.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
try:
            # 方法1: 直链
            url = f"https://music.163.com/song/media/outer/url?id={song_id}"
            resp = self.session.get(url, timeout=15, verify=False, allow_redirects=False)
            if resp.status_code == 302:
                loc = resp.headers.get('Location', '')
                if 'music.126.net' in loc:
Confidence
99% confidence
Finding
This redirect-probing request trusts an HTTPS response without validating the certificate, so a MITM could forge the redirect target. Since the code treats the Location header as a download URL candidate, this can directly influence what content is later retrieved.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
return loc
            # 方法2: 通过详情API
            url = f"https://music.163.com/api/song/enhance/player/url?ids=[{song_id}]&br=320000"
            resp = self.session.get(url, headers={"Referer": "https://music.163.com"}, timeout=15, verify=False)
            data = resp.json()
            return data.get('data', [{}])[0].get('url', '')
        except:
Confidence
99% confidence
Finding
The player URL API response is fetched with TLS verification disabled, so an attacker could substitute arbitrary media URLs in the JSON payload. That enables silent redirection of downloads and undermines the authenticity of retrieved files.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_qq(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://c.y.qq.com/soso/fcgi-bin/client_search_cp?p=1&n=15&w={quote(keyword)}&format=json"
            resp = self.session.get(url, timeout=15, verify=False)
            data = resp.json()
            songs = []
            for item in data.get('data', {}).get('song', {}).get('list', []):
Confidence
99% confidence
Finding
QQ search results are requested with verify=False, allowing network interception and response tampering. Because those results determine later requests and downloads, the impact extends beyond incorrect search output to potentially malicious file retrieval.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# QQ音乐需要特殊签名,这里使用简化方案
            # 通过搜索页面的播放链接
            url = f"https://y.qq.com/n/ryqq/songDetail/{songmid}"
            resp = self.session.get(url, timeout=15, verify=False)
            # 尝试提取音频链接
            match = re.search(r'"url":"(https?://[^"]+\.m4a[^"]*)"', resp.text)
            if match:
Confidence
99% confidence
Finding
This page fetch disables TLS verification before scraping an audio URL from the response. A MITM attacker could inject a crafted URL into the HTML, causing the program to fetch attacker-controlled media content.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
return match.group(1).replace('\\/', '/')
            # 备用方案:使用ws关联接口
            url = f"https://u.y.qq.com/cgi-bin/musicu.fcg?data={quote(json.dumps({'req': {'module': 'CDN.SrfCdnDispatchServer', 'method': 'GetCdnDispatch', 'param': {'guid': '1234567890', 'calltype': 0, 'userip': ''}}, 'req_0': {'module': 'vkey.GetVkeyServer', 'method': 'CgiGetVkey', 'param': {'guid': '1234567890', 'songmid': [songmid], 'songtype': [0], 'uin': '0', 'loginflag': 1, 'platform': '20'}}}, ensure_ascii=False))}"
            resp = self.session.get(url, timeout=15, verify=False)
            data = resp.json()
            purl = data.get('req_0', {}).get('data', {}).get('midurlinfo', [{}])[0].get('purl', '')
            sip = data.get('req', {}).get('data', {}).get('sip', [''])[0]
Confidence
99% confidence
Finding
The fallback QQ API request uses HTTPS without certificate validation, making the returned purl/sip values untrustworthy. Since these values are concatenated into a final download URL, tampering can directly redirect the downloader to malicious content.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_gequbao(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.gequbao.com/s/{quote(keyword)}"
            resp = self.session.get(url, timeout=15, verify=False)
            songs = []
            pattern = r'data-id="(\d+)"[^>]*data-name="([^"]*)"[^>]*data-singer="([^"]*)"'
            for song_id, name, singer in re.findall(pattern, resp.text)[:15]:
Confidence
99% confidence
Finding
The Gequbao search request disables TLS verification, enabling MITM manipulation of returned song IDs and metadata. In this tool, compromised metadata can cascade into unsafe URL retrieval and downloads.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_gequbao(self, song_id: str) -> Optional[str]:
        try:
            url = f"https://www.gequbao.com/api/song/url?id={song_id}"
            resp = self.session.get(url, timeout=15, verify=False)
            return resp.json().get('url', '')
        except:
            return None
Confidence
99% confidence
Finding
This API call fetches a direct song URL over HTTPS with certificate checks disabled. An attacker on the network could replace the URL with arbitrary content sources, resulting in unauthorized or malicious downloads.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_5nd(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.5nd.com/song/0-0-0-0-0-0-0-0-1-0-0-0.html?searchKey={quote(keyword)}"
            resp = self.session.get(url, timeout=15, verify=False)
            songs = []
            # 提取歌曲链接
            pattern = r'href="/song/(\d+)\.htm"[^>]*>([^<]+)</a>'
Confidence
99% confidence
Finding
TLS verification is disabled for 5nd search, so a network attacker can tamper with the HTML and influence which song IDs are processed. That compromises trust in the entire workflow because subsequent steps depend on these identifiers.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_5nd(self, song_id: str) -> Optional[str]:
        try:
            url = f"https://www.5nd.com/song/{song_id}.htm"
            resp = self.session.get(url, timeout=15, verify=False)
            # 提取播放链接
            match = re.search(r'href="(https?://[^"]+\.mp3[^"]*)"', resp.text)
            if match:
Confidence
99% confidence
Finding
This page fetch extracts an MP3 link from unverified HTTPS content. A MITM attacker could inject or alter that link, making the downloader retrieve malicious or unintended files.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_1ting(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.1ting.com/search?q={quote(keyword)}"
            resp = self.session.get(url, timeout=15, verify=False)
            songs = []
            pattern = r'href="/song/(\d+)"[^>]*>([^<]+)</a>'
            for sid, name in re.findall(pattern, resp.text)[:15]:
Confidence
99% confidence
Finding
The 1ting search request uses verify=False, which defeats HTTPS authenticity and permits response tampering. Since parsed results feed later media retrieval, this can indirectly lead to attacker-chosen downloads.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_1ting(self, song_id: str) -> Optional[str]:
        try:
            url = f"https://www.1ting.com/song/{song_id}"
            resp = self.session.get(url, timeout=15, verify=False)
            match = re.search(r'href="(https?://[^"]+\.mp3[^"]*)"', resp.text)
            if match:
                return match.group(1)
Confidence
99% confidence
Finding
Disabling TLS verification while scraping MP3 URLs from a song page allows a MITM to inject arbitrary links into the response. The downloader would then trust and fetch those links, writing the result to disk.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_9ku(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.9ku.com/soso/-k-{quote(keyword)}-k-.htm"
            resp = self.session.get(url, timeout=15, verify=False)
            songs = []
            # 解析歌曲列表
            pattern = r'href="/[a-z]+/(\d+)\.htm"[^>]*title="([^"]+)"'
Confidence
99% confidence
Finding
The 9ku search response is fetched without certificate verification, allowing attackers to alter song listings and identifiers. In a multi-source downloader, this broad trust in unauthenticated metadata increases the chance of malicious redirection.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_9ku(self, song_id: str) -> Optional[str]:
        try:
            url = f"https://www.9ku.com/play/{song_id}.htm"
            resp = self.session.get(url, timeout=15, verify=False)
            match = re.search(r'href="(https?://[^"]+\.mp3[^"]*)"', resp.text)
            if match:
                return match.group(1)
Confidence
99% confidence
Finding
This request parses playback/download URLs from HTML received over HTTPS with verification disabled. A network attacker could inject malicious URLs, leading directly to download of attacker-controlled files.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def search_musicenc(self, keyword: str) -> List[Dict]:
        try:
            url = f"https://www.musicenc.com/search/{quote(keyword)}.html"
            resp = self.session.get(url, timeout=15, verify=False)
            songs = []
            pattern = r'href="/song/(\d+)\.html"[^>]*>([^<]+)</a>'
            for sid, name in re.findall(pattern, resp.text)[:15]:
Confidence
99% confidence
Finding
The MusicEnc search request disables TLS certificate verification, which allows tampering with search results and IDs. Because those IDs drive later URL resolution, the weakness can influence what content is ultimately downloaded.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def get_url_musicenc(self, song_id: str) -> Optional[str]:
        try:
            url = f"https://www.musicenc.com/song/{song_id}.html"
            resp = self.session.get(url, timeout=15, verify=False)
            match = re.search(r'href="(https?://[^"]+\.mp3[^"]*)"', resp.text)
            if match:
                return match.group(1)
Confidence
99% confidence
Finding
This page scrape uses unverified HTTPS before extracting MP3 links, so a MITM attacker can replace the media URL with an arbitrary endpoint. That is dangerous because the tool proceeds to fetch and save the referenced content.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
headers = {"User-Agent": HEADERS["User-Agent"], "Referer": referer}
        
        try:
            resp = self.session.get(url, headers=headers, timeout=60, stream=True, verify=False)
            resp.raise_for_status()
            
            size = int(resp.headers.get('content-length', 0))
Confidence
99% confidence
Finding
The final download request itself disables TLS verification, which is the most direct risk in this file. Even if earlier discovery steps were trustworthy, a MITM attacker could tamper with the actual file transfer and cause corrupted or malicious content to be written to disk without detection.

Static analysis

No suspicious patterns detected.