Back to skill

Security audit

Mc Mod Translate, English to Simplified Chinese

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Minecraft mod translation skill, with expected network lookups and a dictionary download, but users should be aware the downloaded dictionary is not cryptographically verified.

Install only if you are comfortable with the skill contacting GitHub and zh.minecraft.wiki during use. For safer operation, review or pin the dictionary release, verify its checksum independently, and use --no-wiki when you do not want lookup terms sent to the wiki API.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T08 · Insecure Dependencies

Warning
Location
scripts/fetch_dict.py:55
Finding

Downloaded Dictionary Database Is Installed Without Integrity Verification

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_dict.py, lines 55–60 and 96–102
Vulnerability Type: Supply-chain integrity failure
Risk Level: Medium

Vulnerable Code

python
return {
    "tag": tag,
    "published": published,
    "download_url": asset["browser_download_url"],
    "size": asset["size"],
    "digest": asset.get("digest", ""),
}
python
# Verify size
actual_size = os.path.getsize(dest_path + ".tmp")
if actual_size != expected_size:
    print(f"WARNING: Downloaded size ({actual_size}) != expected ({expected_size})", file=sys.stderr)

# Atomic rename
os.replace(dest_path + ".tmp", dest_path)
print(f"Saved to: {dest_path}")

Technical Analysis

The downloader obtains a digest from the GitHub release metadata but never uses it to authenticate the downloaded database. It only compares the downloaded file size with the size reported by the same remote metadata source.

File size is not a cryptographic integrity control. An attacker able to replace the release asset or control the corresponding release metadata can provide a malicious file with the expected size. Furthermore, even when the size differs, the script only prints a warning and still replaces the destination database.

HTTPS protects the connection in transit under normal conditions, but it does not protect against compromise of the upstream repository, release account, or published asset. Because the release is dynamically selected through the latest endpoint, the effective database content can change after this project has been reviewed.

Attack Path

  1. An attacker compromises the upstream release process, repository account, or release asset.
  2. The attacker publishes or replaces Dict-Sqlite.db with manipulated translation records.
  3. A user runs python3 scripts/fetch_dict.py.
  4. The script retrieves the attacker-controlled asset URL and downloads the database.
  5. No cryp ...[truncated 1132 chars]
Remediation
View remediation

Remediation Suggestions

  1. Cryptographically verify the downloaded asset before installation. Parse the release-provided SHA-256 digest and compare it using a constant-time comparison:

    python
    import hashlib
    import hmac
    
    def sha256_file(path):
        digest = hashlib.sha256()
        with open(path, "rb") as source:
            for chunk in iter(lambda: source.read(1024 * 1024), b""):
                digest.update(chunk)
        return digest.hexdigest()
    
    expected_digest = info["digest"]
    if not expected_digest.startswith("sha256:"):
        raise RuntimeError("A valid SHA-256 release digest is required")
    
    expected_hash = expected_digest.split(":", 1)[1].lower()
    actual_hash = sha256_file(dest + ".tmp")
    if not hmac.compare_digest(actual_hash, expected_hash):
        os.remove(dest + ".tmp")
        raise RuntimeError("Downloaded database failed SHA-256 verification")
    
  2. Treat a size mismatch as a fatal error. Delete the temporary file and preserve the existing database rather than continuing to os.replace().

  3. Require a digest instead of accepting an empty value. If trustworthy release metadata does not provide one, distribute a separately authenticated checksum or signature.

  4. For stronger reproducibility, pin a reviewed release tag and expected digest rather than automatically trusting the latest mutable release.

  5. Validate the SQLite file before installation, including its file header and expected schema. Open it in read-only mode and confirm that required tables and columns are present.

  6. Place verification and validation before the atomic replacement so any failure leaves the previously trusted database intact.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill's declared purpose is translation, but its documented behavior also includes downloading and updating a large database from GitHub and performing network lookups against a wiki API. This mismatch is dangerous because it can hide externally reachable behavior and supply-chain interactions behind an innocuous description, reducing reviewer scrutiny and increasing the chance that users or orchestrators permit actions they did not intend.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README states that the skill is for translating mod content from English to Simplified Chinese, and the bilingual description reinforces a fixed target language. Under the policy, forcing a specific language is a natural-language locale constraint unless the user is offered a choice or the limitation is clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs the agent to perform network operations such as downloading a SQLite database from GitHub and querying an external wiki API, but it does not declare any tool scope or allowed-tools boundary. In an agent environment, undeclared network capability increases the risk of unexpected outbound requests, supply-chain exposure, and permission creep because reviewers and policy engines cannot easily constrain what the skill is allowed to access.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill instructs translation specifically from English to Simplified Chinese as a fixed requirement. Under the policy, forcing a specific language or locale without user opt-in is a natural-language policy violation unless the constraint is explicitly justified as region-specific or the user is given a choice.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fetch_dict.py (reported line 33)May include surrounding context.

python
def get_latest_release():
    """Query GitHub API for the latest release info."""
    url = f"https://api.github.com/repos/{REPO}/releases/latest"
    req = urllib.request.Request(url, headers={
        "Accept": "application/vnd.github+json",
        "User-Agent": "mc-mod-translate-skill",

Static analysis

No suspicious patterns detected.