T09 · Insecure Skill Coding Practices
- Location
scripts/make_reel_preview.py:29- Finding
Persistent Temporary Media Artifacts Cause Data Retention and Disk Exhaustion
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed reel-making helper with expected local media generation and optional third-party AI calls, but users should handle output paths and sensitive text carefully.
Install only if you are comfortable with local ffmpeg execution and optional OpenAI/LTX processing. Do not send confidential narration or prompt text to those services unless that is acceptable for your use case, and choose output filenames carefully because the scripts may overwrite existing files. Periodically clean old reelsmith temporary directories if you generate many previews.
scripts/make_reel_preview.py:29Persistent Temporary Media Artifacts Cause Data Retention and Disk Exhaustion
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
'Content-Type': 'application/json',
}
r = requests.post(API_URL, json=payload, headers=headers, timeout=600)
if r.status_code != 200:
raise SystemExit(f'LTX request failed: {r.status_code} {r.text}')
The declared description centers on end-to-end short-form video and reel creation workflows, including concepts, scripts, scene planning, captions, covers, preview videos, narrated reels, and AI-video options. The actual code only accepts text and outputs synthesized speech audio via OpenAI TTS. While narration could be a supporting component of a narrated reel, this code chunk by itself does not implement the broader video-generation functionality described. Its primary purpose is materially narrower and different from the declared skill behavior.
The script writes the final ffmpeg output to a fully user-controlled path with no validation or confinement. In an agent or automated workflow context, this can overwrite arbitrary files writable by the process, enabling data loss, clobbering of application assets, or placement of files in sensitive locations.
concat = work / 'concat.txt'
concat.write_text(''.join([f"file '{c}'\n" for c in clips]))
subprocess.run(['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', str(concat), '-c', 'copy', args.output], check=True)
print(args.output)
The script writes the final media file to a fully user-controlled path and combines this with ffmpeg -y, enabling arbitrary file overwrite wherever the process has permissions. In agent workflows that may accept untrusted or indirect user input, this can be abused to replace or corrupt files outside the intended working directory, making the skill more dangerous because it is built for automated content generation pipelines.
concat = work / 'concat.txt'
concat.write_text(''.join([f"file '{c}'\n" for c in clips]))
subprocess.run(['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', str(concat), '-c', 'copy', args.output], check=True)
print(args.output)
The tool writes concat.txt using unescaped file lines of the form file '{c}' and then invokes ffmpeg with -safe 0, disabling path safety checks. If an attacker can influence file names or the temporary path, specially crafted characters such as single quotes or newlines can break the manifest format and inject additional file directives, leading to unintended local file access or media processing abuse.
concat = work / 'concat.txt'
concat.write_text(''.join([f"file '{c}'\n" for c in clips]))
subprocess.run([
'ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', str(concat), '-c', 'copy', args.output
], check=True)
print(args.output)
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.
ap.add_argument('--output', required=True)
args = ap.parse_args()
subprocess.run([
'ffmpeg', '-y', '-i', args.video, '-i', args.audio,
'-c:v', 'copy', '-c:a', 'aac', '-shortest', args.output
], check=True)
The skill advertises and documents use of shell commands, local file reads/writes, environment variables, and network-backed APIs, but it declares no explicit tool scope or permissions boundary. That creates a least-privilege failure: an agent or runtime may permit broader capability use than reviewers or users expect, increasing the chance of unauthorized file access, secret exposure, or execution of external commands during normal use.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
import requests
API_URL = 'https://api.ltx.video/v1/text-to-video'
def main():
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
'Content-Type': 'application/json',
}
r = requests.post(API_URL, json=payload, headers=headers, timeout=600)
if r.status_code != 200:
raise SystemExit(f'LTX request failed: {r.status_code} {r.text}')
The script sends user-provided prompt text to a third-party video-generation API and authenticates with an API credential, but it provides no user-facing notice about that external transmission. In an agent-skill context, prompts may contain sensitive source material, so undisclosed transfer to an external vendor can create privacy, compliance, and data-handling risk.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
raise SystemExit(f'LTX request failed: {r.status_code} {r.text}')
out = Path(args.output)
out.write_bytes(r.content)
print(str(out))
The script builds an ffmpeg filter expression from scene-derived file paths and then passes it to ffmpeg. Although Python shell injection is avoided, ffmpeg's filter/parser layer is still processing attacker-influenced content, which can lead to parser confusion, failures, or exploitation if ffmpeg has a vulnerable filter parsing bug in the deployed environment.
f":x=(w-text_w)/2:y=(h-text_h)/2"
f":box=1:boxcolor=black@0.55:boxborderw=34"
)
subprocess.run([
'ffmpeg', '-y', '-f', 'lavfi', '-i', f'color=c=black:s=1080x1920:d={args.scene_duration}',
'-vf', draw,
'-frames:v', '1', str(img)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
'-vf', draw,
'-frames:v', '1', str(img)
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess.run([
'ffmpeg', '-y', '-loop', '1', '-i', str(img), '-t', str(args.scene_duration), '-pix_fmt', 'yuv420p', '-vf', 'scale=1080:1920', str(clip)
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
clips.append(clip)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
'-vf', draw,
'-frames:v', '1', str(img)
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess.run([
'ffmpeg', '-y', '-loop', '1', '-i', str(img), '-t', str(args.scene_duration), '-pix_fmt', 'yuv420p', '-vf', 'scale=1080:1920', str(clip)
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
clips.append(clip)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
concat = work / 'concat.txt'
concat.write_text(''.join([f"file '{c}'\n" for c in clips]))
subprocess.run(['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', str(concat), '-c', 'copy', args.output], check=True)
print(args.output)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
concat = work / 'concat.txt'
concat.write_text(''.join([f"file '{c}'\n" for c in clips]))
subprocess.run(['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', str(concat), '-c', 'copy', args.output], check=True)
print(args.output)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
clips = []
opener_clip = work / 'scene-1.mp4'
subprocess.run([
'ffmpeg', '-y', '-loop', '1', '-i', args.opener_image, '-t', str(args.scene_duration), '-pix_fmt', 'yuv420p', '-vf', 'scale=1080:1920', str(opener_clip)
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
clips.append(opener_clip)
The script forces ffmpeg overwrites with -y for both intermediate and final outputs, and accepts a user-controlled output path without any confirmation or safety guard. In an agent or automation context, this can destroy existing files or clobber important media artifacts unexpectedly, especially if parameters are influenced by external input.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
f":x=(w-text_w)/2:y=(h-text_h)/2"
f":box=1:boxcolor=black@0.55:boxborderw=34"
)
subprocess.run([
'ffmpeg', '-y', '-f', 'lavfi', '-i', f'color=c=black:s=1080x1920:d={args.scene_duration}',
'-vf', draw,
'-frames:v', '1', str(img)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
f"drawtext=textfile='{txt}':reload=0:fontcolor=white:fontsize={fontsize}:line_spacing={line_spacing}:"
f"x=(w-text_w)/2:y=(h-text_h)/2:box=1:boxcolor={boxcolor}:boxborderw={boxborderw}"
)
subprocess.run([
'ffmpeg', '-y', '-f', 'lavfi', '-i', f'color=c=black@0.0:s={CANVAS_W}x{CANVAS_H}:d=1,format=rgba',
'-frames:v', '1', '-update', '1', '-vf', vf, str(out)
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
'-pix_fmt', 'yuv420p',
str(out)
]
subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def main():
The final ffmpeg concat call consumes a concat manifest built from file paths without escaping or safe path handling, while explicitly using '-safe 0'. If an attacker can influence clip paths or working paths containing quote/newline characters, they may inject additional concat entries or unexpected file references, causing ffmpeg to read unintended local files or process attacker-chosen inputs.
concat = work / 'concat.txt'
concat.write_text(''.join([f"file '{c}'\n" for c in clips]))
subprocess.run([
'ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', str(concat), '-c', 'copy', args.output
], check=True)
print(args.output)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
ap.add_argument('--output', required=True)
args = ap.parse_args()
subprocess.run([
'ffmpeg', '-y', '-i', args.video, '-i', args.audio,
'-c:v', 'copy', '-c:a', 'aac', '-shortest', args.output
], check=True)
The script sends arbitrary user-supplied text to an external OpenAI service without any visible notice, consent flow, or sensitivity check. If the text includes private, regulated, or confidential content, this can cause unintended data disclosure to a third-party processor.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
input=args.text,
)
out = Path(args.output)
out.write_bytes(speech.read())
print(str(out))
No suspicious patterns detected.