Back to skill

Security audit

混元生3D模型能力

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent for Tencent Hunyuan 3D generation, but its helper script trusts remote response values too broadly and can write or download outside the user’s intended bounds if the API response is compromised or unexpected.

Install only if you are comfortable giving the helper script a Tencent Hunyuan 3D API key and allowing it to write model outputs locally. Prefer temporary or secret-manager-based API key injection over writing secrets into shell startup files, and run the script with an output directory you control. The helper should be updated to validate JobId path components, constrain downloads to trusted HTTPS hosts, and enforce file size/type limits before broad use.

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/generate.py:86
Finding
Unsanitized API response permits arbitrary filesystem paths and unrestricted remote downloads## Vulnerability Details **File Location**: `scripts/generate.py`, lines 86-95 and 192-212 **Vulnerability Type**: Untrusted path construction, unrestricted URL handling, and unbounded download **Risk Level**: Medium ### Vulnerable Code ```python def download_file(url, output_path): """下载文件""" try: req = request.Request(url, headers={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.0' }) with request.urlopen(req, timeout=60) as response: with open(output_path, 'wb') as f: f.write(response.read()) return True except Exception as e: print(f"下载文件失败: {e}") return False ``` ```python job_id = result.get("JobId") if not job_id: print("❌ 未获取到JobId") print(f"响应: {json.dumps(result, indent=2, ensure_ascii=False)}") sys.exit(1) print(f"✅ 任务提交成功,Job ID: {job_id}") # 等待完成 final_result = wait_for_completion(api_key, job_id) if not final_result: sys.exit(1) # 创建输出目录 today = datetime.now().strftime("%Y%m%d") output_dir = Path(args.output) / today / job_id output_dir.mkdir(parents=True, exist_ok=True) # 保存任务信息 info_path = output_dir / "info.json" with open(info_path, "w", encoding="utf-8") as f: json.dump(final_result, f, ensure_ascii=False, indent=2) # 下载3D模型 model_url = final_result.get("ResultUrl", "") if model_url: # 根据URL后缀判断格式 ext = model_url.split('.')[-1].split('?')[0] if '.' in model_url else "glb" model_path = output_dir / f"model.{ext}" if download_file(model_url, model_path): print(f"✅ 已保存: {model_path}") ``` ### Technical Analysis The script treats `JobId` and `ResultUrl` from the remote API as trusted values. `JobId` is directly appended to the user-selected output path. There is no validation requiring it to be a simple identifier and no canonical-path containment check. A response contai ...[truncated 3010 chars]
Remediation
## Remediation Suggestions 1. Validate `JobId` using a strict allowlist suitable for Tencent job identifiers, for example letters, digits, hyphens, and underscores with a conservative maximum length. 2. Reject absolute paths, path separators, `.` components, and `..` components in all remote values used as filenames or directory names. 3. Resolve the base output directory and candidate destination with `Path.resolve()`, then verify that the destination remains beneath the resolved base directory before creating or writing anything. 4. Require model URLs to use HTTPS and allowlist the exact Tencent download hosts documented for the service. 5. Validate every redirect destination rather than only the initial URL. Disable automatic redirects or use a custom redirect handler that reapplies scheme, hostname, port, and IP-range checks. 6. Resolve destination hosts and reject loopback, link-local, multicast, unspecified, and private-network addresses unless such access is explicitly required. 7. Stream downloads in bounded chunks instead of calling `response.read()` without a limit. Abort when a configured maximum model size is exceeded. 8. Check `Content-Length` when present, while still enforcing the limit during streaming because that header may be absent or inaccurate. 9. Restrict output formats to an explicit allowlist such as `glb` and `obj`. Prefer trusted response metadata or a fixed local extension rather than deriving an extension from arbitrary URL text. 10. Write downloads to a safely created temporary file within the validated output directory, verify size and expected format, and atomically rename the file only after validation succeeds. 11. Use exclusive file creation or an explicit overwrite policy to prevent unintended replacement of existing files.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Tainted flow: 'req' from os.environ.get (line 78, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
try:
        req = request.Request(SUBMIT_URL, data=payload, headers=headers, method='POST')
        
        with request.urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode('utf-8'))
    except Exception as e:
        print(f"提交任务失败: {e}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.environ.get (line 78, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
try:
        req = request.Request(SUBMIT_URL, data=payload, headers=headers, method='POST')
        
        with request.urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode('utf-8'))
    except Exception as e:
        print(f"提交任务失败: {e}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.environ.get (line 78, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = request.Request(url, headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.0'
        })
        with request.urlopen(req, timeout=60) as response:
            with open(output_path, 'wb') as f:
                f.write(response.read())
        return True
Confidence
90% confidence
Finding
The script downloads a file from model_url/ResultUrl returned by the remote API without validating the destination host, scheme, size, or content type. If the upstream service is compromised, misconfigured, or can be influenced to return arbitrary URLs, this creates an SSRF-style outbound request/download primitive and may allow retrieval of unexpected or malicious content into the local filesystem.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
�**:
- `HUNYUAN_3D_API_KEY` - 混元3D API Key

**Windows PowerShell**:
```powershell
# 临时设置(当前会话)
$env:HUNYUAN_3D_API_KEY = "sk-xxxxx"

# 永久设置(推荐)
[Environment]::SetEnvironmentVariable("HUNYUAN_3D_API_KEY", "sk-xxxxx", "User")
```

**Linux/Mac**:
```bash
# 临时设置
export HUNYUAN_3D_API_KEY="sk-xxxxx"

# 永久设置(添加到 ~/.bashrc 或 ~/.zshrc)
echo 'export HUNYUAN_3D_API_KEY="sk-xxxxx"' >> ~/.bashrc
source ~/.bashrc
```

### 第四步:验证配置

```powershell
# 检查环境变量
Write-Host "API Key: $($env:HUNYUAN_3D_API_KEY.Substring(0,15))..."

# 测试生成
python scripts/generate.py --mode text --prompt "一只小狗"
```

**如果报错"资源不足"**:服务正在初始化,等待5-10分钟后重试

```bash
python scripts/generate.py --mode text --prompt "一只小狗"
```

如果看到「任务提交成功」,说明配置正确!

## 功能

- **文生3D**:通过文本描述生成3D模型
- **图生3D**:通�
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill metadata advertises required environment access and the documentation instructs running local scripts that perform network requests and write output files, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens least-privilege boundaries and makes it harder for a host agent or reviewer to understand and constrain what the skill is allowed to access.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documentation recommends persisting the API key by appending it directly to ~/.bashrc or ~/.zshrc without warning about credential exposure. This can leak secrets through shell history, dotfile backups, repo sync, shared accounts, or accidental disclosure during troubleshooting, increasing the blast radius beyond a single session.

Tainted flow: 'info_path' from os.environ.get (line 207, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
# 保存任务信息
    info_path = output_dir / "info.json"
    with open(info_path, "w", encoding="utf-8") as f:
        json.dump(final_result, f, ensure_ascii=False, indent=2)
    
    # 下载3D模型
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.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The file’s docstring and all user-facing CLI messages are written in Chinese, which imposes a specific language on users with no opt-in or alternative locale handling. Under the policy rule, forcing a language without user choice is a natural-language policy concern.

Static analysis

No suspicious patterns detected.