T09 · Insecure Skill Coding Practices
- Location
scripts/gequhai_crawler.py:294- Finding
Hard-Coded Synology NAS Credentials in Source Code
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill matches its music-download purpose, but it embeds NAS credentials and exposes unauthenticated controls that can change files on a Synology NAS.
Review this carefully before installing. Do not use it as published with real NAS access: remove embedded credentials, rotate the exposed NAS password, require authentication for the service, bind it to localhost or a protected interface, use HTTPS to the NAS, disable wildcard CORS, and require confirmation before any download, rename, move, or overwrite operation.
scripts/gequhai_crawler.py:294Hard-Coded Synology NAS Credentials in Source Code
scripts/gequhai_crawler.py:318NAS Passwords and Session Identifiers Transmitted over Plaintext HTTP
service/main.py:103Unauthenticated API Endpoints Trigger Privileged NAS Operations
scripts/gequhai_crawler.py:539Automatic File Moves Delete Sources and Permit Destination Overwrites
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
If the actual behavior is fixed-keyword scraping with local file output instead of general user-driven search/download, then the skill is materially more deceptive than its description suggests. Misrepresented automation that writes files can be abused or accidentally triggered in ways users did not consent to.
The script contains hard-coded Synology NAS IP, username, and password, then uses them to automatically authenticate and administer the NAS. Anyone with access to the skill source, logs, backups, or package can recover these credentials and gain unauthorized access to the NAS, potentially compromising stored data and other NAS services.
The skill silently uses embedded NAS credentials to log into a private storage system without any disclosure or consent flow. Even if intended for convenience, hidden automatic authentication to a personal NAS is dangerous because users may not realize the skill has privileged access to internal storage and can perform actions under those credentials.
The skill can list, rename, and move files on the Synology NAS using generic path parameters, which exceeds the stated purpose of music search/download. Because these functions operate on arbitrary paths and are coupled with authenticated NAS access, misuse or future agent exposure could alter or relocate non-music files across the NAS.
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.
The skill declares networked search/download and NAS-related behavior but does not define any explicit tool scope or permissions boundary. In an agent environment, undeclared access to network, file read/write, or environment data increases the chance of over-privileged execution and makes it harder for users and reviewers to understand what the skill can actually do.
The trigger description is broad enough that the skill may activate on common music-related requests, including benign questions that do not imply consent to network access, scraping, or NAS download actions. In context, this is more dangerous because the skill can initiate downloads or external requests tied to a local NAS, which are higher-impact side effects than simple recommendation behavior.
The skill description does not prominently warn users that requests may result in content being sent to a Synology NAS. Because device-targeted downloads affect local infrastructure and storage, insufficient disclosure can lead to unintended actions on a private system and weakens meaningful user consent.
The documentation exposes a hard-coded custom header secret presented as required to access the target API. Publishing a bypass secret or anti-abuse token in a skill both encourages circumvention of service controls and creates a reusable credential that others can abuse, potentially leading to unauthorized API access or account/IP blocking.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
}
try:
resp = requests.post(url, data=data, timeout=15)
result = resp.json()
if result.get("success"):
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
}
try:
resp = requests.post(url, data=data, timeout=15)
result = resp.json()
if result.get("success"):
The code automatically renames downloaded files and moves them into a final NAS directory without prompting the user at execution time. In the context of an agent skill, this creates hidden side effects on user storage and increases the risk of accidental overwrites, file confusion, or unintended modification of NAS contents.
A song download request triggers a chain of side effects: adding a NAS download task, deriving a filename from a remote URL, renaming the downloaded file, and moving it to another directory. This behavior goes beyond simple retrieval and is risky because a user asking to download music may not expect authenticated write operations on their NAS to occur automatically.
The Accept-Language header is hard-coded to "zh-CN,zh;q=0.9", which forces a specific locale preference regardless of user choice. This is a natural-language locale policy concern because the skill does not offer any language or locale selection or explain why a China-specific locale is required.
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
result = {"id": song_id}
# 提取标题和歌手
match = __import__("re").search(r"window\.mp3_title\s*=\s*['\"]([^'\"]+)['\"]", resp.text)
if match:
result["title"] = match.group(1)
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
if match:
result["title"] = match.group(1)
match = __import__("re").search(r"window\.mp3_author\s*=\s*['\"]([^'\"]+)['\"]", resp.text)
if match:
result["artist"] = match.group(1)
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
if match:
result["artist"] = match.group(1)
match = __import__("re").search(r"window\.play_id\s*=\s*['\"]([^'\"]+)['\"]", resp.text)
if match:
result["play_id"] = match.group(1)
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
if match:
result["play_id"] = match.group(1)
match = __import__("re").search(r"window\.mp3_type\s*=\s*(\d+)", resp.text)
if match:
result["type"] = int(match.group(1))
No suspicious patterns detected.