T01 · Skill Instruction Hijacking
- Location
SKILL.md:487- Finding
Security-analysis instruction hijacking
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is mostly a Manim animation helper, but it includes purpose-mismatched audit guidance and an unsafe deletion helper that could remove files outside the intended project area.
Install only if you are comfortable reviewing the helper code first. Avoid using untrusted scene or branch names with ManimProject, do not enable remote TTS for confidential narration unless you accept sending text to the provider, and prefer pinned/hash-locked dependencies before using it in a sensitive environment.
SKILL.md:487Security-analysis instruction hijacking
references/manim_versioning.py:527Path traversal enables recursive deletion outside branch storage
requirements.txt:9Mutable dependencies and downloaded font artifacts lack immutable integrity verification
Referenced artifact was not completely inspected
The installable skill is the **directory that contains `SKILL.md`** (often `.../recursive-maths-animator/` inside a Git clone), not the repository root above it
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).
manim-voiceover caches generated TTS audio in the `media/voiceovers/` directory:
- Identical text will not be regenerated
- Modified text triggers automatic regeneration
- Clear cache: `rm -rf media/voiceovers/`
### SRT Subtitle Auto-Generation
The README states that voiceover is generated automatically via GTTSService but does not warn users that narration text may be transmitted to an external third-party text-to-speech provider. In a skill that may be used with proprietary, personal, or confidential content, this omission creates a real data exposure risk because users may unknowingly send sensitive text off-box.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Create virtual environment
python3.12 -m venv .venv
source .venv/bin/activate
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
For system-wide access:
# Copy to Claude Code skills
cp -r references/pattern_library ~/.claude/skills/recursive-maths-animator/references/
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
For system-wide access:
# Copy to Claude Code skills
cp -r references/pattern_library ~/.claude/skills/recursive-maths-animator/references/
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
- **F — Soft enterprise** (Roboto, warm cream — existing default)
Also offer **aspect ratio** (16:9, 1:1, 9:16) and **tone** (calm / punchy). Let the user pick or mix.
3. **Wait for approval** — Only after the user confirms (or says “use A + 1:1 + calm”) do you: write **`ANIMATION_BRIEF.md`** (filled) + **`DESIGN_THEME.md`** (locked), then implement the scene.
4. **Use the maths engine** — Prefer Manim-native motion: `MathTex` / `Tex`, `NumberPlane`, `ParametricFunction`, `Transform` / `ReplacementTransform`, `Indicate`, `ShowPassingFlash`, `LaggedStart`, updaters. Avoid “generic UI explainer” unless that is what they asked for. See **`references/manim_guide.md`** for patterns.
5. **Shareable quality** — **MP4 at `-qh` / `--quality h`** is the default deliverable for “looks good.” GIF is for **layout checks** only; re-encoding with aggressive `ffmpeg` **crushes** gradients and dark minimal palettes. If they need a small GIF, render a **short** clip, limit colors in the scene, or share **MP4** / link instead.
The template hard-codes GTTSService(lang='en', slow=True), which instructs generated projects to use English voiceover by default. This is a natural-language locale constraint presented as the standard template behavior, and the file does not pair it with a user choice or opt-in at that point.
The legacy template repeats the same forced English setting with GTTSService(lang='en', slow=True). Because this applies across generated scenes unless manually edited, it violates the language/locale policy criterion requiring user choice or clear justification.
The document states that the skill does not call cloud LLM APIs from Python, yet elsewhere it explicitly documents optional Gemini integration requiring google-genai and GEMINI_API_KEY. That inconsistency can mislead operators into underestimating network/data-exfiltration risk and approving execution in environments where outbound API access is restricted.
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
| Document | Purpose | Location |
|----------|---------|----------|
| **README.md** | Main project overview with video gallery | `/README.md` |
| **SKILL.md** | Complete skill documentation | `~/.claude/skills/recursive-maths-animator/SKILL.md` |
| **QUICK_REFERENCE.md** | Pattern usage guide | `references/pattern_library/QUICK_REFERENCE.md` |
| **FINAL_RELENTLESS_REPORT.md** | Testing evidence | `.training/FINAL_RELENTLESS_REPORT.md` |
| **COMPREHENSIVE_PATTERN_LEARNINGS.json** | Machine-readable learnings | `.training/learnings/` |
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
### 2. Educational Series
Create a series of math/statistics videos:
- Episode 1: Normal Distribution (DistributionAnimation)
- Episode 2: Sampling (SamplingVisualization)
- Episode 3: Correlation (TableToScatterPlotPattern)
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
"""Import the module for a given scheme key."""
meta = get_scheme(key)
mod_name = meta["module"]
__import__(mod_name)
return sys.modules[mod_name]
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"""Download a zip file from Google Fonts to ``dest``. Returns path."""
dest.parent.mkdir(parents=True, exist_ok=True)
cmd = ["curl", "-L", "-o", str(dest), url]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Failed to download font from {url}: {result.stderr}")
return dest
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"""Download a zip file from Google Fonts to ``dest``. Returns path."""
dest.parent.mkdir(parents=True, exist_ok=True)
cmd = ["curl", "-L", "-o", str(dest), url]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Failed to download font from {url}: {result.stderr}")
return dest
The example scene demonstrates SwissContainers.pill_label("v1.0", position=RIGHT * 3 + UP * 2), implying that pill_label accepts a position parameter. However, the actual function signature at L243-L244 defines only text, bg_color, text_color, and border_color, so the documented example contradicts the implementation and would fail at runtime.
The service sends arbitrary user-supplied text to Google's Gemini API for TTS generation, but the public interface and top-level documentation do not clearly warn that input content is transmitted to a third-party service. In contexts where the text may contain secrets, proprietary material, or sensitive personal data, this can lead to unintended data disclosure across trust boundaries.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Solution:
# Linux
sudo apt install fonts-noto-cjk
# macOS (built-in PingFang SC, usually OK)
The brief template states 'Use English only,' which imposes a language constraint regardless of user preference. The policy allows locale constraints only when the user is offered a choice or when the constraint is clearly justified; neither is present here.
The module-level description at L002-L004 presents this as a Git-based version control system for Manim projects. The install_scheme_fonts path adds a distinct capability to fetch/install external font assets via a referenced font catalog, which is not an obvious requirement of version control itself.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cli_format,
"--disable_caching",
]
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.project_path)
if result.returncode != 0:
print(f"Render error: {result.stderr}")
The code deletes a branch directory with shutil.rmtree, which is a destructive operation, but this method provides no confirmation prompt, warning print, or explanatory comment/docstring communicating that local branch contents will be permanently removed. Under the code-file criteria, destructive operations should have some visible disclosure unless already clearly warned elsewhere in the file.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
file1 = scene_path / "versions" / f"v{v1}.py"
file2 = scene_path / "versions" / f"v{v2}.py"
result = subprocess.run(
["diff", "-u", str(file1), str(file2)],
capture_output=True, text=True
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def _git(self, *args) -> subprocess.CompletedProcess:
"""Run git command in project directory"""
return subprocess.run(
["git"] + list(args),
cwd=self.project_path,
capture_output=True
The code explicitly configures the speech service with GTTSService(lang='en'), which hard-codes English output. This is a natural-language locale constraint and there is no indication in the file that users can choose another language or that the English-only behavior is justified.
No suspicious patterns detected.