T09 · Insecure Skill Coding Practices
- Location
scripts/tts.py:64- Finding
Caller-Controlled Output Path Allows Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/tts.py:64-78
Vulnerability Type: Unrestricted file write and overwrite
Risk Level: MediumVulnerable Code
python out_path = os.path.abspath(args.out) os.makedirs(os.path.dirname(out_path), exist_ok=True) try: with urllib.request.urlopen(req, timeout=120) as resp: audio = resp.read() except Exception as e: print(f"ERROR: ElevenLabs request failed: {e}", file=sys.stderr) return 1 with open(out_path, "wb") as f: f.write(audio)Technical Analysis
The
--outargument is fully controlled by the caller. The script converts this value to an absolute path but does not verify that the resolved destination remains inside the workspace or another approved output directory.os.makedirs()can create attacker-selected parent directories wherever the process has permission, whileopen(out_path, "wb")silently truncates an existing destination before writing the returned audio. There are also no checks for symbolic links or for whether the destination already exists.Consequently, a caller who can influence the script arguments can direct a successful ElevenLabs response into any file writable by the account running the Skill. Converting a path with
os.path.abspath()normalizes it but does not impose a security boundary.The credential-related instructions in
SKILL.md:9-15andSKILL.md:27-34do not independently constitute a vulnerability. They direct the operator to configure the required ElevenLabs API key in the runtime environment, and the implementation reads only the relevant environment variables. The script does not directly open or enumerate~/.openclaw/.env.Attack Path
- An attacker or untrusted caller supplies TTS text and chooses a sensitive writable path as
--out, such as a user configuration file or an application-owned file. os.path.abspath(args.out)accepts the path without enforc ...[truncated 1052 chars]
- An attacker or untrusted caller supplies TTS text and chooses a sensitive writable path as
- Remediation
View remediation
Remediation Suggestions
- Define a fixed, trusted output root inside the workspace, such as
workspace/media/elevenlabs-tts. - Resolve both the trusted root and requested output path with
pathlib.Path.resolve(). - Reject any destination that is not a descendant of the trusted root, using
Path.relative_to()or an equivalent containment check. - Reject symbolic-link destinations and inspect existing parent components to prevent symlink-based escapes.
- Use exclusive file creation mode (
"xb") by default so existing files cannot be silently truncated. Require an explicit trusted overwrite option when replacement is genuinely necessary. - Generate server-side filenames rather than accepting arbitrary absolute paths from untrusted callers.
- Apply restrictive file permissions and run the Skill under a dedicated, least-privileged service account.
- Validate the response status and content type before writing the response body, then write to a securely created temporary file within the approved directory and atomically rename it to the final destination.
- Define a fixed, trusted output root inside the workspace, such as
