Back to skill

Security audit

二维码生成器

Security checks for vulnerabilities and agentic risk

Overview

The skill does generate QR codes, but its image mode can read and encode arbitrary small local files, not just verified images.

Review before installing. Use only with trusted, explicit image paths, avoid pointing it at secrets or private config files, and prefer a version that validates image contents, restricts allowed paths, and creates temporary output files securely.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
agent.py:9
Finding

Arbitrary Local File Read Through Unvalidated Image Path

Content
View full analysis

Vulnerability Details

File Location: agent.py, lines 9-20 and 40-54
Vulnerability Type: Arbitrary local file read caused by insufficient file-type and path validation
Risk Level: Medium

Vulnerable Code

python
def file_to_base64(file_path):
    """将本地文件转换为 base64 字符串(含 data URL 头)"""
    with open(file_path, 'rb') as f:
        data = f.read()
    b64 = base64.b64encode(data).decode('utf-8')
    mime = mimetypes.guess_type(file_path)[0] or 'application/octet-stream'
    return f"data:{mime};base64,{b64}"

def image_to_qr_data(image_path):
    """处理图片,返回要编码的数据"""
    base64_str = file_to_base64(image_path)
    if len(base64_str) <= MAX_QR_BYTES:
        return base64_str
    else:
        return f"图片太大无法直接存储,请上传至图床后使用 URL 生成二维码。"
python
def handle_call(args: dict):
    """技能入口函数"""
    content = args.get("content", "")
    image_path = args.get("image", "")

    # 优先处理图片
    if image_path:
        if not os.path.exists(image_path):
            return {"error": f"图片文件不存在:{image_path}"}
        file_size = os.path.getsize(image_path)
        if file_size > 10 * 1024 * 1024:
            return {"error": "图片太大,请选择小于10MB的图片"}
        qr_data = image_to_qr_data(image_path)
        if qr_data.startswith("图片太大"):
            return {"message": qr_data}

Technical Analysis

The image argument is treated as an arbitrary local filesystem path. The implementation only checks whether the path exists and whether its reported size is below 10 MB. It does not verify that the path points to an authorized file, that it is located within an approved directory, or that its contents are a valid image.

mimetypes.guess_type() does not validate file contents; it merely infers a MIME type from the filename. Consequently, a caller can provide the path of any file readable by the skill process. The file is opened and read in full before the QR-capacity check is per ...[truncated 1437 chars]

Remediation
View remediation

Remediation Suggestions

  1. Restrict file access to explicitly approved directories or files rather than accepting unrestricted absolute paths.
  2. Resolve the canonical path with os.path.realpath() or pathlib.Path.resolve() and verify that it remains within an authorized root directory.
  3. Define and enforce a symlink policy. If symlinks are unnecessary, reject them with os.path.islink() and use platform-safe file-opening controls where available.
  4. Validate file contents as an image before encoding them. For example, open the file with Pillow, call verify(), and only process supported formats.
  5. Do not rely on filename extensions or mimetypes.guess_type() for security validation.
  6. Perform authorization and size checks before reading file contents, and stream bounded input where practical.
  7. Run the skill under a dedicated least-privilege account that cannot read credentials, private keys, or unrelated application data.
  8. Consider accepting image bytes or controlled upload handles instead of raw host filesystem paths.

T09 · Insecure Skill Coding Practices

Warning
Location
agent.py:22
Finding

Predictable Non-Atomic File Creation in Shared Temporary Directory

Content
View full analysis

Vulnerability Details

File Location: agent.py, lines 22-36
Vulnerability Type: Unsafe temporary-file creation and potential symlink overwrite
Risk Level: Medium

Vulnerable Code

python
def generate_qr(data: str) -> str:
    """生成二维码,返回图片路径"""
    qr = qrcode.QRCode(
        version=None,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(data)
    qr.make(fit=True)

    img = qr.make_image(fill_color="black", back_color="white")
    temp_dir = tempfile.gettempdir()
    file_path = os.path.join(temp_dir, f"qr_{hash(data)}.png")
    img.save(file_path)
    return file_path

Technical Analysis

The application constructs an output filename in the shared system temporary directory using hash(data) and then opens that path through Pillow's img.save(). It does not use an exclusive, atomic temporary-file creation API.

Python's hash randomization makes the hash value less predictable across separate interpreter processes, but it does not provide a secure file-creation guarantee. The same input in the same process produces the same path, returned paths may become known to other callers, hash collisions are possible, and the target path can be replaced between operations.

If a local attacker can create or replace entries in the shared temporary directory and identify or reuse a generated filename, the attacker may pre-create that path as a symbolic link. Saving the image can then follow the link and overwrite another file writable by the skill process.

Attack Path

  1. A local attacker observes a previously returned QR output path, causes a known input to be processed, or otherwise identifies a filename used by the running process.
  2. The attacker creates or replaces that temporary pathname with a symbolic link to another file.
  3. The attacker triggers QR generation for data that maps to the same pathname ...[truncated 744 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create the output atomically with tempfile.NamedTemporaryFile(suffix=".png", delete=False) or tempfile.mkstemp().
  2. Preserve exclusive creation semantics and save through the securely opened file object or descriptor rather than closing it and reopening the pathname.
  3. Do not derive security-sensitive temporary filenames from hash(data).
  4. If multiple artifacts must be grouped, create a private directory with tempfile.mkdtemp() and restrictive permissions.
  5. Ensure generated files have least-privilege permissions and define a cleanup policy to remove stale QR images.
  6. Avoid following symbolic links when creating output files, using platform-specific no-follow controls where necessary.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (5)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill's human-readable docstrings and user-facing messages are written only in Chinese, including error and status text returned to the caller. This imposes a specific language choice without offering the user a language option or documenting a justified locale restriction.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code reads arbitrary local files from a provided path, base64-encodes their contents, and later writes a generated QR image to a temporary file. Although these actions are central to the skill's functionality, the file itself contains no user-facing prompt, logging, or warning about reading local files and creating output files on disk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This Python file contains user-facing natural-language strings and documentation entirely in Chinese, including the module docstring and printed example labels. Under the policy rules, forcing a specific language without opt-in or an explicit region-specific justification is a natural-language policy issue.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency specification for Pillow uses a lower-bound only constraint (>=10.0.0), which makes builds non-reproducible and allows future installs to resolve to unexpected versions. While this is not an exploit by itself, it increases supply-chain risk and can unintentionally introduce vulnerable or incompatible releases over time.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
qrcode[pil]>=7.4.2
Pillow>=10.0.0

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
89% confidence
Finding

Pillow has a history of security advisories, and because the manifest does not pin the package version, there is no assurance that installations will avoid affected releases. In a skill that processes images or QR-code generation via qrcode[pil], this uncertainty is somewhat more relevant because Pillow is likely to be installed and used directly.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.