Back to skill

Security audit

ai-shifu-course-creator

Security checks across malware telemetry and agentic risk

Overview

The skill is mostly coherent for AI-Shifu course work, but it automatically reports account-linked usage telemetry and can perform live course changes with weak confirmation boundaries.

Review before installing. Use the default AI-Shifu host or only a trusted HTTPS SHIFU_BASE_URL, set AI_SHIFU_SKILL_TELEMETRY=off if you do not want command telemetry, and require explicit human confirmation before publish, archive, delete, reorder, or existing-course import. Install current patched dependency versions rather than the oldest versions allowed by requirements.txt.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (19)

Tainted flow: 'headers' from os.environ.get (line 524, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
files = {"file": (filename, file_bytes, mime)}
    data = {"resource_id": resource_id} if resource_id else None
    try:
        resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)
    except requests.RequestException as e:
        print(f"API transport error: POST /upfile ({e})")
        sys.exit(1)
Confidence
90% confidence
Finding
resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)

Tainted flow: 'headers' from os.environ.get (line 524, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
try:
        url = f"{base_url}/api/shifu/shifus?limit=1"
        headers = {"Cookie": f"token={token}", "Content-Type": "application/json"}
        resp = requests.get(url, headers=headers, timeout=15)
    except requests.RequestException as e:
        print(f"Token status: unknown (network error: {e})")
        sys.exit(2)
Confidence
91% confidence
Finding
resp = requests.get(url, headers=headers, timeout=15)

Tainted flow: 'url' from os.environ.get (line 265, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
"python": platform.python_version(),
            },
        }
        requests.post(
            url,
            json={"type": "event", "payload": payload},
            headers={"User-Agent": _user_agent(agent)},
Confidence
92% confidence
Finding
requests.post( url, json={"type": "event", "payload": payload}, headers={"User-Agent": _user_agent(agent)}, timeout=REQUEST_TIMEOUT, )

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares no permissions in this file, yet its documented startup flow instructs the agent to read multiple local files and the static findings indicate broader capabilities including file write, network, env, and shell. That mismatch weakens user consent and reviewability: a user may trigger a skill that can access local/runtime resources and external services without clear disclosure.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The described purpose is course authoring/management, but the static findings indicate hidden behaviors such as outbound telemetry, remote update checks, token/JWT lifecycle handling, and broader metadata searches. Undisclosed telemetry and remote communications are especially risky in a skill that may handle course content, account context, learner analytics, and authentication material, because they can leak sensitive data or expand the trust boundary silently.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The analytics-query command exposes arbitrary creator-analytics DSL execution to anyone using this skill, which is broader than the stated course lifecycle management need. Because the DSL can query backend analytics tables, this increases the chance of overbroad access to creator data, learner metrics, or metadata beyond the minimum necessary for normal course operations.

Intent-Code Divergence

High
Confidence
97% confidence
Finding
The documentation claims telemetry does not send a distinct identifier tied to identity, but `distinct_id()` prefers the logged-in platform `user_id` from `SHIFU_TOKEN`. In this skill, that mismatch is dangerous because it can mislead reviewers and users into consenting to telemetry under false privacy assumptions while an account-linked identifier is transmitted externally.

Intent-Code Divergence

Medium
Confidence
84% confidence
Finding
The code comments frame JWT parsing as merely 'no verification', but the operational effect is that the extracted raw `user_id` is used as the telemetry distinct ID and sent to external analytics. In a course-authoring skill that may be used by many creators, this understates meaningful privacy impact and can hide account-linkage behavior from operators and users.

Vague Triggers

High
Confidence
88% confidence
Finding
The trigger conditions are extremely broad, covering nearly any mention of AI-Shifu, course analytics, deployment, progress, or related Chinese terms. Overbroad activation increases the chance the skill runs in contexts the user did not intend, potentially pulling in authentication, course targeting, analytics, or state-changing workflows unnecessarily.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill advertises deployment, publishing, reordering, archiving, metadata management, and other impactful platform operations without any upfront warning in this file that these actions can modify live course state. In a course-management context, accidental invocation could lead to unauthorized or unintended production changes affecting learners, revenue, visibility, or analytics integrity.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The skill mandates that all user-facing output be written in `resolved_target_language` without stating that this language must be derived from an explicit user choice. That can override the user's preferred language, misrepresent sensitive analytics or refusal messages, and create ambiguity in a privacy-sensitive workflow where precise wording matters.

External Transmission

Medium
Category
Data Exfiltration
Content
"python": platform.python_version(),
            },
        }
        requests.post(
            url,
            json={"type": "event", "payload": payload},
            headers={"User-Agent": _user_agent(agent)},
Confidence
89% confidence
Finding
requests.post( url, json=

Env Variable Harvesting

High
Category
Data Exfiltration
Content
skill and from the website shares one distinct id. Only the anonymous
    fallback carries an `a:` prefix.
    """
    token = os.environ.get("SHIFU_TOKEN") or _token_from_env_file()
    if token:
        user_id = _jwt_user_id(token)
        if user_id:
Confidence
96% confidence
Finding
os.environ.get("SHIFU_TOKEN

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| --- | --- |
| SMS send succeeds | Wait for the code; do not send another SMS. |
| User asks to resend before entering three wrong codes | Explain that delivery can take 60 seconds and wait. |
| `smsSendTooFrequent` | Wait 60 seconds, then retry the same command without asking for the phone again. |
| First or second wrong code | Ask the user to re-enter the code; do not resend. |
| Third consecutive wrong code | Run `login --phone <phone>` once more; this is the final SMS for the session. |
| Login or verification has a network failure | Stop the login attempt and retry `verify` later; do not spend another SMS slot. |
Confidence
78% confidence
Finding
without asking

Credential Access

High
Category
Privilege Escalation
Content
def _token_from_env_file() -> str | None:
    """Read SHIFU_TOKEN from the skill's .env without requiring dotenv."""
    try:
        for line in ENV_FILE.read_text(encoding="utf-8").splitlines():
            key, sep, value = line.partition("=")
Confidence
95% confidence
Finding
.env

Known Vulnerable Dependency: requests==2.28 — 8 advisory(ies): CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi); CVE-2026-25645 (Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility func) +5 more

High
Category
Supply Chain
Confidence
86% confidence
Finding
requests==2.28

Known Vulnerable Dependency: python-dotenv==1.0 — 2 advisory(ies): CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)

Medium
Category
Supply Chain
Confidence
80% confidence
Finding
python-dotenv==1.0

Known Vulnerable Dependency: Pillow==10.3.0 — 10 advisory(ies): CVE-2026-55379 (Pillow `BdfFontFile`: `Image.new()` called without `_decompression_bomb_check()`); CVE-2026-55798 (Pillow: WindowsViewer.get_command() OS command injection via unescaped shell pat); CVE-2026-54060 (Pillow: `FontFile.compile()`: `Image.new()` called without `_decompression_bomb_) +7 more

High
Category
Supply Chain
Confidence
88% confidence
Finding
Pillow==10.3.0

Known Vulnerable Dependency: pillow-heif==0.13 — 2 advisory(ies): CVE-2026-28231 (pillow-heif: Integer Overflow in Encode Path Buffer Validation Leads to Heap Out); CVE-2026-28231 (pillow_heif is a Python library for working with HEIF images and plugin for Pill)

Critical
Category
Supply Chain
Confidence
93% confidence
Finding
pillow-heif==0.13

VirusTotal

VirusTotal findings are pending for this skill version.

View on VirusTotal

Static analysis

No suspicious patterns detected.