other
- Location
README.md:31- Finding
Misleading Local-Processing Claim Conceals Cloud Disclosure
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a coherent video-clipping skill, but it needs review because its privacy and install disclosures understate cloud processing and mutable dependency risk.
Review before installing. Use this only for media you are comfortable sending to OpenAI for transcription and Anthropic for transcript analysis, and prefer an isolated environment with pinned dependency versions. Be aware that the current artifacts do not implement the advertised silence/breath removal and may leave source media, audio, transcripts, metadata, and generated clips on disk.
README.md:31Misleading Local-Processing Claim Conceals Cloud Disclosure
README.md:38Unpinned Third-Party Installation Commands Create Supply-Chain Exposure
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
전반적인 주요 목적은 선언과 거의 일치한다. 실제 코드도 한국어 YouTube/로컬 영상을 처리하고, Whisper 기반 자막 추출, Claude 기반 바이럴 구간 선정, ffmpeg 클립 생성, 3색 자막, 점수/이유 메타데이터 저장을 수행한다. 그러나 선언에서 명시한 '무음/숨소리 구간 제거'는 코드에 없다. extract_clip의 주석에는 '무음 압축'이 언급되지만 실제 ffmpeg 호출은 원본 오디오를 그대로 AAC로 재인코딩할 뿐 무음 탐지, 음성 활동 검출, 숨소리 제거, 자동 컷 편집 같은 처리가 전혀 없다. 이는 사용자 기대에 영향을 주는 실질적 기능 불일치다. 반면 YouTube URL/로컬 파일 지원, Clawitzer 연결 가능성(경로 추가 및 3색 규칙 재사용 성격), 자막 스타일링 등은 대체로 설명과 부합한다. 따라서 부분적이지만 중요한 설명-행동 불일치가 있다고 판단한다.
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
parser.add_argument("--n-clips", type=int, default=10, help="추출할 클립 수 [기본: 10]")
parser.add_argument("--lang", default="ko", help="자막 언어 [기본: ko]")
parser.add_argument("--dry", action="store_true", help="자막 추출만 (클립 미생성)")
parser.add_argument("--no-check", action="store_true", help="환경 검사 스킵")
args = parser.parse_args()
if not args.url and not args.file:
The description explicitly positions the skill as '한국어 YouTube 영상' and the README repeatedly frames outputs such as Korean subtitles as a fixed behavior. There is no user opt-in, language choice, or explanation that the locale restriction is required for a region-specific compliance or similar justified constraint.
L030 explicitly says '원본 음성 유지 ... 무음 압축 없음', indicating silence is not compressed or removed. This conflicts with the stated skill description that includes '무음/숨소리 구간 제거'. The documentation presents contradictory intent about whether the tool alters audio continuity.
The README claims the tool runs locally and that videos are not uploaded to external servers, but the documented use of OpenAI Whisper and Anthropic Claude APIs means audio and/or transcript data is sent to third parties. This is dangerous because users may process sensitive or copyrighted media under a false privacy assumption, leading to unintended data disclosure and consent/compliance issues.
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
The skill explicitly instructs the agent to use shell commands, inspect environment state, install packages, download media, and write outputs, but it does not declare any tool scope or permission boundaries. In practice this increases the blast radius of prompt-triggered execution because the agent may invoke powerful capabilities without a least-privilege contract or user-visible guardrails.
Broad trigger phrases increase the chance that the skill activates in loosely related contexts and starts workflows involving downloads, shell execution, file writes, and API transmission without sufficiently specific user intent. Because this skill handles external URLs/files and invokes powerful tooling, ambiguous activation is more dangerous than for a read-only or local-only skill.
The skill downloads media and sends audio/transcript content to external providers, but the description does not clearly warn users that their content will be transmitted off-platform and stored in output artifacts. This creates privacy and compliance risk, especially for local files or non-public videos that may contain sensitive or copyrighted material.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
errors = []
# yt-dlp
r = subprocess.run(["yt-dlp", "--version"], capture_output=True)
if r.returncode != 0:
errors.append("yt-dlp 없음: pip install yt-dlp")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
errors.append("yt-dlp 없음: pip install yt-dlp")
# ffmpeg
r = subprocess.run(["ffmpeg", "-version"], capture_output=True)
if r.returncode != 0:
errors.append("ffmpeg 없음: apt install ffmpeg")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
errors.append("ffmpeg 없음: apt install ffmpeg")
# libass (자막 burn-in에 필요)
r = subprocess.run(["ffmpeg", "-filters"], capture_output=True, text=True)
if "subtitles" not in r.stderr:
print(" ⚠ ffmpeg libass 없음 — 자막 burn-in 불가 (SRT로 대체)")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if os.path.exists(p):
return p
# 시스템 폰트 검색
r = subprocess.run(["fc-list", ":lang=ko"], capture_output=True, text=True)
for line in r.stdout.splitlines():
if ".ttf" in line or ".ttc" in line:
return line.split(":")[0].strip()
The script passes a user-supplied URL directly to yt-dlp, which then performs network retrieval against attacker-controlled destinations. While this is not shell injection, it can enable SSRF-style access to internal resources or unexpected local/protocol handling depending on yt-dlp support and runtime network reachability.
e = end or "99:59:59"
cmd += ["--download-sections", f"*{s}-{e}"]
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0:
print(" ✗ 다운로드 실패:\n", r.stderr[-500:])
raise RuntimeError("yt-dlp 다운로드 실패")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def get_video_duration(path: str) -> float:
cmd = ["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", path]
r = subprocess.run(cmd, capture_output=True, text=True)
data = json.loads(r.stdout)
return float(data["format"]["duration"])
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# 오디오 추출 (MP3로 변환, Whisper 25MB 제한 대응)
audio_path = str(out_dir / "audio.mp3")
subprocess.run([
"ffmpeg", "-y", "-i", video_path,
"-q:a", "0", "-map", "a",
"-b:a", "64k", # 낮은 비트레이트로 용량 절약
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
while offset < duration:
chunk_path = str(out_dir / f"audio_chunk_{int(offset)}.mp3")
subprocess.run([
"ffmpeg", "-y", "-i", audio_path,
"-ss", str(offset), "-t", str(chunk_sec),
"-b:a", "64k", chunk_path,
The prompts explicitly instruct the model to act as a Korean short-form content editor, score clips by fit for Korean viewers, and generate titles in Korean. This imposes a specific language/locale policy in the skill's behavior rather than offering the user a choice, which matches the policy-violation criterion for forced language/locale.
The manifest explicitly claims '무음/숨소리 구간 제거', but the actual extraction path only trims the selected time range, rescales video, burns subtitles, and re-encodes audio. The inline comment at L635 even states the original audio is kept and that no silence compression is applied, so this advertised behavior is not implemented.
The ffmpeg filter string embeds ass_path directly into -vf as ass={ass_path} without escaping for ffmpeg filter syntax. Because ass_path is filesystem-derived and temporary paths can legally contain special characters such as : or ', this can break parsing and, in less controlled environments, create filter-argument injection behavior or unreliable execution.
)
# 영상 + 오디오 한번에 (원본 음성 유지, 무음 압축 없음)
subprocess.run([
"ffmpeg", "-y",
"-ss", str(start_sec), "-t", str(duration),
"-i", source_video,
The section header/comment at L628 describes the ffmpeg step as including '무음 압축', but the immediately following comment at L635 says the original audio is preserved with no silence compression, and the ffmpeg arguments contain no silence-removal or compression filters. This is active documentation inconsistency about what the code does.