T09 · Insecure Skill Coding Practices
- Location
scripts/send2tv.py:106- Finding
Unauthenticated Media Exposure on All Network Interfaces
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This TV-casting skill mostly does what it claims, but it uses broad local-network serving and automatic process termination in ways users should review before installing.
Review this skill before installing, especially on shared machines or networks. Avoid sending sensitive text, images, or audio, do not run it as root, and be aware it can kill whatever process is already using port 8082. TTS mode should only be used if you trust the separately installed edge-tts converter.
scripts/send2tv.py:106Unauthenticated Media Exposure on All Network Interfaces
scripts/send2tv.py:84Predictable Shared Temporary Files Permit Symlink Attacks and Cross-Process Data Exposure
scripts/send2tv.py:157Unconditional Termination of Unrelated Processes Using the HTTP Port
scripts/send2tv.py:261Unpinned External TTS Skill Is Located in Mutable Directories and Executed
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
Push text, images, or audio to Huawei Smart Screen V75 (or other DLNA-compatible TVs) via UPnP AVTransport protocol.
# Text (Chinese supported)
python3 scripts/send2tv.py "快去写作业!"
# Text with custom font size
python3 scripts/send2tv.py "Warning!" --font-size
The skill documentation indicates it invokes local scripts, writes/serves files, and starts a local HTTP server, yet the manifest declares no explicit tool scope or permissions. In an agent environment, missing scope declarations can cause the agent to invoke shell and file-write capabilities without clear user-facing constraints or policy review, increasing the chance of unintended command execution or data exposure.
The trigger phrases are broad and can match common user requests such as 'send to TV' or 'display on TV' without clarifying that content will be broadcast to a specific local-network device. In an agent-routing setting, this can cause accidental invocation and unintended disclosure of private text, images, or audio to a shared television.
The skill description does not clearly warn that using it starts an HTTP server and transmits user-provided text, images, or audio over the local network to a TV at a fixed IP. Users may unknowingly expose sensitive content to other devices on the LAN or display private information on a shared screen, which is a meaningful privacy and safety risk in this skill's context.
This finding is substantiated by the code path that kills any process using the chosen HTTP port before serving DLNA content. In the context of a skill whose purpose is only to host temporary media for a TV, that extra disruptive capability is unjustified and can cause denial of service to unrelated local applications.
The local process-termination behavior expands the skill's authority beyond its stated function and creates avoidable system impact. Because it is automatic and silent, a user invoking a 'send to TV' action may unintentionally kill local services such as development servers, dashboards, or other apps bound to port 8082.
The script unconditionally runs fuser -k against the configured HTTP port before starting its server, which terminates whatever local process is bound there. This is a real unsafe capability because a TV-casting helper does not need blanket authority to kill unrelated local services, and if the port is occupied by another application the skill will disrupt it without validation or consent.
def start_server(port=HTTP_PORT):
"""Start HTTP server for DLNA push."""
subprocess.run(["fuser", "-k", f"{port}/tcp"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(0.5)
httpd = ReuseAddrTCPServer(("0.0.0.0", port), DLNAHandler)
t = threading.Thread(target=httpd.serve_forever, daemon=False)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# Convert to mp3 using ffmpeg if available
if shutil.which('ffmpeg'):
subprocess.run([
'ffmpeg', '-y', '-i', audio_path,
'-codec:a', 'libmp3lame', '-qscale:a', '2',
output_path
The natural-language interface and code set the default voice to zh-CN-XiaoxiaoNeural, and the usage/help text presents Chinese voices as the default experience. This imposes a specific language/locale choice unless the user explicitly overrides it, which matches the policy concern for forced language/locale behavior.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd.extend(['--rate', rate])
print(f"Running TTS: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"TTS stderr: {result.stderr}")