Back to skill

Security audit

元镜 yotta-mirror

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a local education analytics tool, but users should review its weak student-identifier pseudonymization and broad installer behavior before installing.

Install only if you are comfortable with a local tool processing student assessment data. Prefer --agent or --dir over -g, review the exact target directory first, and do not treat --anonymize output as fully anonymous for external sharing; keep reports and source data under the same controls as sensitive educational records.

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

Warning
Location
scripts/yotta_mirror.py:235
Finding

Deterministic Unsalted Student Pseudonyms Permit Re-identification and Cross-Report Linkage

Content
View full analysis

Vulnerability Details

File Location: scripts/yotta_mirror.py:235-238
Supporting Workflow Documentation: SKILL.md:89, references/privacy.md:17-19
Vulnerability Type: Weak pseudonymization of sensitive student identifiers
Risk Level: Medium

Vulnerable Code

python
def anonymize_id(student):
    digest = hashlib.sha256(str(student).encode("utf-8")).hexdigest()
    return "S-" + digest[:8]

Technical Analysis

The --anonymize feature hashes each student identifier directly with SHA-256, without a secret key or dataset-specific random salt, and retains only the first eight hexadecimal characters. This produces a deterministic 32-bit pseudonym.

Student names, enrollment numbers, and other identifiers often have small or predictable input spaces. Anyone who receives a report can enumerate likely identifiers, calculate the same SHA-256 prefixes, and compare them with the report values. Truncating the digest to 32 bits also creates a material collision risk as the number of processed identifiers grows.

Because the transformation is deterministic and not scoped to a particular institution, dataset, or report, identical source identifiers produce identical pseudonyms across reports. This permits cross-report correlation even when the recipient cannot immediately recover the underlying identifier.

The documented workflow recommends using --anonymize before externally sharing reports. Consequently, pseudonymized identifiers may cross from the trusted local environment to external recipients, while the original identifiers are expected to remain confidential.

Attack Path

  1. An authorized user processes a score sheet using the --anonymize option.
  2. The Skill replaces each student identifier with S- followed by the first eight hexadecimal characters of its unsalted SHA-256 digest.
  3. The resulting report is shared with an external recipient under the assumption that the identifier ...[truncated 1025 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace direct SHA-256 hashing with HMAC-SHA-256 using a cryptographically random secret key:
    python
    digest = hmac.new(secret_key, student.encode("utf-8"), hashlib.sha256).hexdigest()
    
  2. Use a separate secret key for each institution or dataset to prevent cross-dataset correlation.
  3. Retain a longer digest segment, such as at least 128 bits, to reduce collision risk.
  4. Store the HMAC key separately from exported reports and source datasets, with access restricted to authorized personnel.
  5. If reproducibility is unnecessary, generate random per-report identifiers and maintain any identifier mapping in a protected local file.
  6. Describe this feature as pseudonymization rather than irreversible anonymization, and warn that pseudonymized reports remain sensitive.
  7. Provide a key-management option or explicit dataset-scope parameter so users can control whether identifiers remain linkable across authorized reports.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (26)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

A skill that claims to only analyze student data locally but actually performs mkdir/cp/rm operations, enumerates supported AI-agent environments, and installs files into agent directories creates a trust-boundary violation. In this context, the privacy- and safety-oriented wording makes the mismatch more dangerous because it can cause operators to underestimate non-analytics side effects, including unauthorized modification of local agent configuration or skill state.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

A skill that claims to only analyze student data locally but actually performs mkdir/cp/rm operations, enumerates supported AI-agent environments, and installs files into agent directories creates a trust-boundary violation. In this context, the privacy- and safety-oriented wording makes the mismatch more dangerous because it can cause operators to underestimate non-analytics side effects, including unauthorized modification of local agent configuration or skill state.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

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).

Content

Scanner excerpt · install.sh (reported line 66)May include surrounding context.

sh
install_to() {
  mkdir -p "$1/$SKILL_NAME"
  cp -r "$SOURCE_DIR/." "$1/$SKILL_NAME/"
  rm -rf "$1/$SKILL_NAME/.git"
  echo "installed -> $1/$SKILL_NAME"
}

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

The README instructs users to execute npx -y @yottameta/yotta-mirror without pinning a specific package version. This creates a supply-chain risk: users may unknowingly install and run whatever version is current at execution time, including a compromised or maliciously published update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

This installation example also uses npx -y @yottameta/yotta-mirror without a pinned version, so execution depends on the latest package available from the registry at runtime. In CI or automated agent environments, that can lead to unreviewed code execution if the package is updated or the registry/package account is compromised.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

README recommends executing npx -y @yottameta/yotta-mirror without pinning an exact package version. This can cause users to fetch and run whatever version is current at install time, creating a supply-chain risk if a malicious or compromised release is published later.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

This second npx -y @yottameta/yotta-mirror example has the same issue: it instructs users to execute an unpinned package directly from the registry. If the package account, dependency chain, or a future published version is compromised, users could run attacker-controlled code during installation or execution.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

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.

Content

Scanner excerpt · bin/install.js (reported line 25)May include surrounding context.

js
const AGENT_DIRS = {
  claude:    { label: 'Claude Code',      dirs: ['.claude/skills'] },
  cursor:    { label: 'Cursor',           dirs: ['.cursor/skills', '.agents/skills'] },
  codex:     { label: 'Codex',            dirs: ['.codex/skills'] }, // 特判:$CODEX_HOME/skills
  gemini:    { label: 'Gemini CLI',       dirs: ['.gemini/skills', '.agents/skills'] },
  goose:     { label: 'Goose',            dirs: ['.config/goose/skills', '.agents/skills'] },
  amp:       { label: 'Amp',              dirs: ['.config/agents/skills', '.agents/skills'] },

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes yotta-mirror as a zero-dependency, local, offline student-diagnostics skill, but this file's primary behavior is creating directories and copying the package into agent skill locations. That packaging/deployment behavior is not part of the stated analytical function and materially expands what the skill does beyond analytics.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The global mode propagates the skill into all known user-level agent directories in one run, broadening the package's footprint far beyond a single requested target. In the context of a local analytics skill, this creates unnecessary deployment reach and raises the risk of accidental installation into tools the user did not intend to modify, which could affect trust boundaries across multiple agents.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes an offline, local analytics skill for transforming assessment data into diagnostic reports, with explicit limits like no networking and no model calls. This script instead creates directories, copies the entire skill into agent skill folders, and deletes .git, which is operational installation behavior not reflected in the skill's claimed analytical scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script removes the target skill directory's .git folder during installation with rm -rf, which is a destructive operation. While the script comments describe installation paths, there is no explicit user-facing warning or confirmation that repository metadata in the destination will be deleted.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest frames the skill as a zero-dependency local analysis tool, but this code can mass-install itself across numerous known agent directories. That deployment capability is materially different from the stated purpose of producing student diagnostic reports and should be disclosed if included.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

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.

Content

Scanner excerpt · install.sh (reported line 124)May include surrounding context.

sh
echo "完成。"; return
  fi
  local installed=0 d
  for d in .claude/skills .cursor/skills .codex/skills .config/goose/skills .config/agents/skills .opencode/skills .codeium/windsurf/skills .workbuddy/skills .kiro/skills .traecli/skills .gemini/skills .trae-cn/skills .qwen/skills .comate/skills .codebuddy/skills .kimi/skills .agents/skills; do
    if [ -d "$d" ]; then install_to "$d"; installed=1; fi
  done
  if [ "$installed" = "0" ]; then

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description lists triggers such as 'analysing class scores or homework accuracy', 'finding weak knowledge points', and 'producing a learning-diagnostics report' without a constrained activation mechanism or explicit exclusion examples. In a manifest file, these broad natural-language triggers could match many ordinary requests and cause unintended invocation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This file presents all user-facing instructions, examples, and error explanations exclusively in Chinese. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains user-facing natural-language descriptions, errors, and rendered report content entirely in Chinese, including the module docstring and CLI/report strings. Under the policy, forcing a specific language or locale without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file uses Chinese throughout and does not indicate any user choice or opt-in for language. The policy for natural-language violations applies to all file types, and forcing a single language without user opt-in can be a locale-policy issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The README header explicitly labels the skill language as English while offering Chinese only as an alternate linked document. This can be read as a default language constraint without presenting language choice as an opt-in or explaining a justified locale limitation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.