Back to skill

Security audit

Animated Sticker Maker

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its sticker-making purpose, but one packaging script can overwrite or recursively delete caller-selected local paths without an enforced output boundary.

Review before installing. Use this only in a contained project workspace, keep --output under a disposable or dedicated output directory, and avoid pointing it at existing folders. The publisher should add an enforced output root, ownership markers before deletion/replacement, overwrite confirmation, and pinned dependency versions.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/package_sticker.py:581
Finding

Unrestricted Output Path Permits Arbitrary Directory Replacement and Recursive Deletion

Content
View full analysis
int: final_output = args.output.resolve() final_output.parent.mkdir(parents=True, exist_ok=True) failed_output = final_output.with_name(f"{final_output.name}.failed") with tempfile.TemporaryDirectory( prefix=f".{final_output.name}.staging-", dir=final_output.parent, ) as temporary: staged_output = Path(temporary) / final_output.name staged_args = copy.copy(args) staged_args.output = staged_output result = build_candidate(staged_args) if result != 0: if failed_output.exists(): shutil.rmtree(failed_output) staged_output.replace(failed_output) print( "Technical validation failed; existing package preserved. Inspect " f"{failed_output / 'validation' / 'report.json'}" ) return result previous_output = Path(temporary) / "previous-package" if final_output.exists(): final_output.replace(previous_output) try: staged_output.replace(final_output) except Exception: if previous_output.exists() and not final_output.exists(): previous_output.replace(final_output) raise if failed_output.exists(): shutil.rmtree(failed_output) ``` ### Technical Analysis The `--output` command-line argument is converted to an absolute path with `resolve()`, but it is not constrained to an authorized package-output directory. Resolving the path only normalizes it; it does not establish a security boundary. The function subsequently performs destructive operations on caller-selected paths: - An existing `final_output` i ...[truncated 2721 chars]
Remediation
View remediation
.failed`. - Create uniquely named failure directories, such as `.failed-`. - If stale failure artifacts must be removed, validate their ownership marker first. 5. **Require explicit overwrite authorization** - Fail safely when the output already exists unless an explicit `--overwrite` option is provided. - Even with `--overwrite`, only replace a destination verified as an application-owned package. 6. **Preserve recoverable backups** - Keep replaced packages in a persistent backup location rather than inside a temporary directory that is automatically deleted. - Delete backups only after an explicit retention policy or user confirmation. 7. **Add security regression tests** - Verify that output paths outside the authorized root are rejected. - Verify that symlink-based escapes are rejected. - Verify that existing unmarked directories are never replaced. - Verify that unrelated `.failed` directories are never recursively de ...[truncated 10 chars]
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is about generating an animated sticker package from an image and motion prompt. The supplied code does not perform any image processing, motion synthesis, sticker creation, animation generation, or invocation gating. Instead, it implements artifact integrity/fingerprinting utilities: loading JSON metadata, validating package-relative file paths, reading referenced files, and computing deterministic SHA-256 digests over package contents, render frames, and export artifacts. This is a materially different primary purpose and introduces undeclared capabilities related to integrity checking and file hashing.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for an animated sticker maker that takes a reference image plus motion prompt and produces a transparent animated sticker package under explicit invocation conditions. The supplied code instead is a standalone Python script for removing a flat chroma background from one image. It has no animation logic, no sticker packaging, no motion-prompt handling, and no trigger/invocation enforcement related to animated-sticker-maker. Its primary purpose is materially different from the declared purpose, so this is a clear mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description is for a generation skill that makes one animated sticker package from a static image and motion prompt, with explicit invocation restrictions. The supplied code does not generate a sticker from user inputs of that kind. Instead, it is an export utility operating on an already-built package on disk, reading source frames and motion.json, checking validation reports and artifact fingerprints, resizing and quantizing frames, writing a constrained GIF and optional preview PNG, and emitting an export report JSON. This is a materially different primary purpose and adds undeclared capabilities around validation management and platform export. Trigger behavior cannot be verified from this code chunk, but the behavior shown does not match the declared functionality.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code’s core behavior is an offline packager/validator for an animated sticker package. It expects --frames-dir, --motion, and --reference-image inputs; loads a structured motion.json; resolves and validates existing PNG frames; computes alpha/transparency metrics; writes normalized source assets; creates contact sheets and JSON validation reports; and encodes a WEBP sticker. The reference image is only recorded/copied as metadata and is not used to derive animation. There is no handling of a natural-language motion prompt, no image-to-animation generation, and no skill-trigger gating logic. Because the declared purpose centers on creating a sticker package from one static reference image plus one natural-language motion prompt, while the actual code assumes pre-authored frames and structured metadata and adds validation/reporting functionality, the description does not accurately represent the implemented behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is an animated sticker generation skill triggered only by explicit invocation. The supplied code does not generate stickers, process images, interpret motion prompts, or build sticker packages. Instead, it is a report/workflow utility for recording visual validation results tied to artifact integrity checks. This is a materially different primary purpose and includes undeclared capabilities around report mutation, validation gating, and fingerprint verification. Therefore the description does not accurately represent the code.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 11)May include surrounding context.

md
Resolve every script and reference path against the directory containing this `SKILL.md`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 26)May include surrounding context.

md
Use Python 3.10 or newer plus the packages in `requirements.txt` for deterministic processing. Do not make OpenCV a required dependency.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill explicitly instructs the host to read local files, write packages and reports, and access network resources to verify platform constraints, but it declares no tool permissions or allowed-tools scope. In a skill ecosystem, missing scope boundaries increases the chance the host grants broader capabilities than necessary, enabling unintended file-system access or outbound requests during execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill's short description and default prompt are written only in Chinese, which indicates a fixed language/locale presentation without any visible user opt-in or explanation that the skill is intended exclusively for a Chinese-language context. This matches the policy category for language or locale constraints imposed without explicit choice or justification.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

Pillow has a history of image-parsing vulnerabilities, including memory corruption, resource exhaustion, and in some versions code-execution issues. Because the requirement allows a broad range (>=10.0,<13) rather than a specifically audited version, it is not possible to verify from this file alone that deployed environments avoid affected releases; this matters more here because the skill likely handles untrusted image input.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency specification for numpy is open-ended (>=1.24) and does not pin to a specific version, which makes builds non-reproducible and can allow installation of a vulnerable or unexpected release over time. In a skill that processes user-supplied images and animation data, dependency drift increases supply-chain risk and makes it harder to verify whether known security fixes are present.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
Pillow>=10.0,<13
numpy>=1.24

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

NumPy also has known advisories across some historical releases, and the unpinned requirement prevents verification of which exact version will be installed. While NumPy is generally less exposed than an image decoder in this context, untrusted media-processing workflows still benefit from deterministic, patched dependencies.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/record_visual_validation.py (reported line 37)May include surrounding context.

python
"diagnostic export from an unvalidated source cannot become deliverable"
        )

    notes = {field: getattr(args, field).strip() for field in NOTE_FIELDS}
    empty_notes = [field for field, note in notes.items() if not note]
    if empty_notes:
        raise ValueError(

Static analysis

No suspicious patterns detected.