Back to skill

Security audit

魔搭图片生成

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill appears purpose-aligned, but it persists an API key in a local plaintext file without strong POSIX permission handling and sends user prompts to an external API with limited disclosure and scoping.

Review before installing. Use this only if you are comfortable sending prompts, model settings, and your ModelScope token to ModelScope. Prefer a protected environment variable or key manager over --api-key or --save-key, run it in a dedicated virtual environment, and avoid prompts containing private or proprietary information.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_qwen.py:49
Finding

ModelScope API Key Stored with Potentially Unsafe POSIX Permissions in Qwen Generator

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_qwen.py:49-63 and scripts/generate_qwen.py:158
Vulnerability Type: Plaintext credential storage with insufficient permission enforcement
Risk Level: Medium

Vulnerable Code

python
CONFIG_DIR = Path.home() / ".modelscope"
CONFIG_FILE = CONFIG_DIR / "api_key"
python
def save_api_key(api_key: str):
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    CONFIG_FILE.write_text(api_key)
    if sys.platform == "win32":
        import stat
        os.chmod(CONFIG_FILE, stat.S_IREAD | stat.S_IWRITE)

The key can also be provided as a command-line argument:

python
parser.add_argument("--api-key", help="API Key")

Technical Analysis

The --save-key operation writes the ModelScope API key to ~/.modelscope/api_key as plaintext. Explicit permission hardening is performed only when sys.platform == "win32". On POSIX systems, the resulting directory and file permissions depend on the process umask and any pre-existing directory or file permissions.

Under a permissive umask or unsafe pre-existing permissions, other local accounts or processes may be able to read the credential. Supplying the key through --api-key also places the secret in the process command line, where it may be exposed through shell history, process inspection, logging, or monitoring software.

No evidence shows that the script intentionally sends the credential to an unrelated party. The bearer token is sent to the declared ModelScope HTTPS API, which is necessary for the advertised image-generation functionality. The weakness concerns local credential handling.

Attack Path

  1. A user invokes generate_qwen.py --save-key SECRET, or supplies the token through --api-key SECRET.
  2. The script writes the token to ~/.modelscope/api_key without enforcing restrictive POSIX permissions, or the command is retained in shell history and process metadata.
  3. A local account or process with access to t ...[truncated 833 chars]
Remediation
View remediation

Remediation Suggestions

  • On POSIX systems, create ~/.modelscope with mode 0700 and the key file with mode 0600.
  • Use atomic, exclusive file creation to prevent symlink and pre-existing-file permission issues.
  • Verify the ownership and permissions of both the directory and key file before reading or writing credentials.
  • Apply equivalent restrictive ACLs on Windows rather than relying only on generic read/write mode flags.
  • Prefer an operating-system credential manager or keyring instead of a plaintext file.
  • Avoid accepting secrets directly through command-line arguments. Support hidden interactive input, standard input, an OS keyring, or a protected environment variable instead.
  • Update documentation to warn that prompts are transmitted to ModelScope and that command-line secrets may be recorded in shell history.

Example POSIX hardening:

python
CONFIG_DIR.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(CONFIG_DIR, 0o700)

fd = os.open(CONFIG_FILE, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with os.fdopen(fd, "w", encoding="utf-8") as key_file:
    key_file.write(api_key)
os.chmod(CONFIG_FILE, 0o600)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_tongyi.py:49
Finding

ModelScope API Key Stored with Potentially Unsafe POSIX Permissions in Tongyi Generator

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_tongyi.py:49-63 and scripts/generate_tongyi.py:158
Vulnerability Type: Plaintext credential storage with insufficient permission enforcement
Risk Level: Medium

Vulnerable Code

python
CONFIG_DIR = Path.home() / ".modelscope"
CONFIG_FILE = CONFIG_DIR / "api_key"
python
def save_api_key(api_key: str):
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    CONFIG_FILE.write_text(api_key)
    if sys.platform == "win32":
        import stat
        os.chmod(CONFIG_FILE, stat.S_IREAD | stat.S_IWRITE)

The key can also be provided as a command-line argument:

python
parser.add_argument("--api-key", help="API Key")

Technical Analysis

The Tongyi generator duplicates the credential-handling implementation from the Qwen generator. The API token is written as plaintext, while explicit permission handling is conditional on Windows. On POSIX systems, access restrictions are determined by the current umask and the state of any existing directory or file.

Consequently, a permissive local configuration can leave the token readable by unintended users or processes. Passing the token through --api-key may additionally expose it in command history, process listings, telemetry, or execution logs.

The network use itself is consistent with the declared functionality: the token and prompt are sent to https://api-inference.modelscope.cn/ over HTTPS to request image generation. No unrelated exfiltration destination was identified.

Attack Path

  1. A user stores a token using the Tongyi generator or supplies it on the command line.
  2. The plaintext token is created under permissions inherited from an unsafe umask or pre-existing filesystem state, or it is recorded in process or shell metadata.
  3. Another local user, compromised process, or log reader retrieves the token.
  4. The attacker authenticates to ModelScope as the victim.
  5. The attacker consumes service quota or perfo ...[truncated 540 chars]
Remediation
View remediation

Remediation Suggestions

  • Enforce mode 0700 on the configuration directory and 0600 on the key file on POSIX systems.
  • Create the credential file atomically and reject symbolic links or files not owned by the current user.
  • Validate existing file ownership and permissions before loading a stored key.
  • Use restrictive Windows ACLs for the Windows implementation.
  • Store credentials in an operating-system keyring where possible.
  • Deprecate secret-bearing command-line options in favor of hidden interactive input, protected environment variables, standard input, or keyring lookup.
  • Ensure error messages and logs never include authorization headers or token values.

T08 · Insecure Dependencies

Note
Location
SKILL.md:68
Finding

Unpinned Runtime Dependencies Installed Without Integrity Verification

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:68-72
Vulnerability Type: Unpinned third-party dependencies and missing package integrity controls
Risk Level: Low

Vulnerable Code

bash
pip install requests pillow

Technical Analysis

The installation instructions request the latest versions of requests and pillow resolved from the user's active pip configuration. No version constraints, lock file, hashes, or explicit trusted package index are provided.

The package names are legitimate and there is no evidence that the project intentionally references a malicious or typosquatted dependency. However, the installation is not reproducible and relies on mutable upstream packages and the user's configured index. A compromised upstream release, malicious package mirror, unsafe pip configuration, or incompatible future release could introduce unexpected code into the Skill's runtime environment.

Python package installation may execute package build logic, and imported packages execute with the privileges of the user running the Skill.

Attack Path

  1. A user follows the documented pip install requests pillow instruction.
  2. Pip resolves packages from the currently configured package index without checking project-supplied hashes.
  3. An upstream account, package artifact, configured mirror, or dependency in the resolution chain is compromised or substituted.
  4. Malicious installation or import-time code executes under the user's account.
  5. The malicious package can access files, environment variables, network resources, and credentials available to that user.

This path depends on an external package or repository compromise; no malicious dependency is present in the audited project itself.

Impact Assessment

If the dependency supply chain is compromised, code can execute with the same privileges as the user installing or running the Skill. This could expose the ModelScope API key, prompts, generated files, environment var ...[truncated 224 chars]

Remediation
View remediation

Remediation Suggestions

  • Provide a reviewed requirements or lock file with exact dependency versions.
  • Include cryptographic hashes and install with hash verification, for example:
bash
python -m pip install --require-hashes -r requirements.txt
  • Generate and review the lock file using a reproducible dependency-management process.
  • Install dependencies in a dedicated virtual environment rather than the global Python environment.
  • Document the expected Python version and supported dependency versions.
  • Use the official package index explicitly in trusted deployment instructions, while ensuring organization-specific mirrors are authenticated and controlled.
  • Periodically scan pinned direct and transitive dependencies for known vulnerabilities and update them through a reviewed process.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_qwen.py (reported line 97)May include surrounding context.

python
payload["loras"] = loras
    
    # 发起异步请求
    resp = requests.post(
        f"{BASE_URL}v1/images/generations",
        headers={**headers, "X-ModelScope-Async-Mode": "true"},
        data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_tongyi.py (reported line 97)May include surrounding context.

python
payload["loras"] = loras
    
    # 发起异步请求
    resp = requests.post(
        f"{BASE_URL}v1/images/generations",
        headers={**headers, "X-ModelScope-Async-Mode": "true"},
        data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_qwen.py (reported line 109)May include surrounding context.

python
# 轮询状态
    max_attempts = 60
    for i in range(max_attempts):
        result = requests.get(
            f"{BASE_URL}v1/tasks/{task_id}",
            headers={**headers, "X-ModelScope-Task-Type": "image_generation"},
        )

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_tongyi.py (reported line 109)May include surrounding context.

python
# 轮询状态
    max_attempts = 60
    for i in range(max_attempts):
        result = requests.get(
            f"{BASE_URL}v1/tasks/{task_id}",
            headers={**headers, "X-ModelScope-Task-Type": "image_generation"},
        )

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documents capabilities that rely on environment variables, local file reads/writes, shell commands, and outbound network access, but it does not declare any explicit tool scope or permission boundaries. In an agent environment, this increases the chance of over-privileged execution and makes it harder for users or the platform to understand what the skill is allowed to access before activation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger description is broad enough to match many normal conversations about drawing, pictures, or image generation, which can cause the skill to activate unexpectedly. Because the skill can send prompts to an external service and handle credentials or files, accidental invocation may disclose user content or perform actions the user did not clearly intend.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation states that prompts are sent to the external ModelScope API but does not clearly warn users that their text may leave the local environment. This creates a privacy and data-handling risk, especially if users include sensitive, personal, or proprietary information in prompts without realizing it will be transmitted to a third party.

Content

No source excerpt is available for this finding.

Tainted flow: 'image_url' from requests.get (line 120, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
92% confidence
Finding

The script takes image_url from a remote API response and fetches it directly without validating the host, scheme, or content type. If the upstream service is compromised, misbehaves, or an attacker can influence output_images, this can enable server-side request forgery to arbitrary URLs and unsafe processing of attacker-controlled image data by Pillow.

Content

Scanner excerpt · scripts/generate_qwen.py (reported line 123)May include surrounding context.

python
image_url = data["output_images"][0]
            print(f"下载图片: {image_url}")
            
            img_resp = requests.get(image_url)
            img_resp.raise_for_status()
            
            image = Image.open(BytesIO(img_resp.content))

Tainted flow: 'task_id' from requests.post (line 103, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/generate_qwen.py (reported line 109)May include surrounding context.

python
# 轮询状态
    max_attempts = 60
    for i in range(max_attempts):
        result = requests.get(
            f"{BASE_URL}v1/tasks/{task_id}",
            headers={**headers, "X-ModelScope-Task-Type": "image_generation"},
        )

Tainted flow: 'task_id' from requests.post (line 103, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/generate_tongyi.py (reported line 109)May include surrounding context.

python
# 轮询状态
    max_attempts = 60
    for i in range(max_attempts):
        result = requests.get(
            f"{BASE_URL}v1/tasks/{task_id}",
            headers={**headers, "X-ModelScope-Task-Type": "image_generation"},
        )

Tainted flow: 'image_url' from requests.get (line 120, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
91% confidence
Finding

The script fetches image_url directly from API response data and performs requests.get(image_url) without validating the scheme, host, or whether it points to an expected ModelScope-controlled domain. If the upstream API, transport, or response is compromised, this can become an SSRF-style outbound fetch to arbitrary URLs, potentially exposing internal network reachability or downloading unsafe content.

Content

Scanner excerpt · scripts/generate_tongyi.py (reported line 123)May include surrounding context.

python
image_url = data["output_images"][0]
            print(f"下载图片: {image_url}")
            
            img_resp = requests.get(image_url)
            img_resp.raise_for_status()
            
            image = Image.open(BytesIO(img_resp.content))

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill metadata and instructions are presented entirely in Chinese, and there is no indication that users may choose another language or locale. This can be a language-policy issue when a skill implicitly constrains interaction language without opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This file contains natural-language instructions, usage text, and argument help in Chinese only. Under the policy, forcing a specific language without opt-in can be a locale/language policy violation when no alternative or justification is provided.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.