Back to skill

Security audit

image_to_ppt

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent as an image-to-PPT converter, but it can upload any readable local file to a configurable external service without validating that the file is an image or requiring explicit confirmation.

Only install this if you are comfortable sending selected files to SCNet's remote service. Use it only with non-sensitive image files, keep SCNET_API_BASE fixed to the official HTTPS endpoint unless you fully trust the alternative, and confirm the exact file path before each run.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:282
Finding

Caller-Controlled Path Allows Arbitrary Local File Upload

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 140-151 and 282-290
Vulnerability Type: Missing file-type and sensitive-path validation
Risk Level: Medium

Complete Code Snippet

python
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type is None:
    mime_type = 'application/octet-stream'

try:
    with open(file_path, 'rb') as f:
        files = {
            'file': (os.path.basename(file_path), f, mime_type)
        }
        data = {
            'ocr_type': ocr_type,
        }
        response = requests.post(url, headers=headers, data=data, files=files, timeout=60)
python
ocr_type = sys.argv[1]
file_path = sys.argv[2]

if ocr_type not in SUPPORTED_TYPES:
    sys.exit(f"Error: unsupported ocrType '{ocr_type}', available values: {', '.join(SUPPORTED_TYPES.keys())}")

if not os.path.isfile(file_path):
    sys.exit(f"Error: file does not exist - {file_path}")

config = load_config()

Technical Analysis

The Skill declares that IMAGE_TO_PPT accepts an image, and its documentation identifies JPEG, PNG, BMP, TIFF, and WebP as supported formats. The implementation, however, only verifies that the supplied path points to a regular file.

mimetypes.guess_type() is based on the filename extension and is not a security validation mechanism. Unknown files are explicitly accepted as application/octet-stream. The script does not:

  • Allowlist supported image extensions.
  • Validate the file signature or decoded image format.
  • Reject known-sensitive files or directories.
  • Restrict input to an approved workspace.
  • Request confirmation when a path is outside the expected input area.

Consequently, any file readable by the process can be submitted to the remote conversion endpoint if its path is supplied as the filePath argument. This exceeds the minimum file-access scope required for an image-to-PPT conversion Skill.

Attack Path

...[truncated 1041 chars]

Remediation
View remediation

Remediation Suggestions

  1. Enforce an explicit allowlist of supported extensions such as .jpg, .jpeg, .png, .bmp, .tif, .tiff, and .webp.
  2. Validate actual file signatures using a maintained image parser rather than trusting extensions or mimetypes.
  3. Reject files that cannot be decoded as a supported image.
  4. Resolve the path with Path.resolve() and, where practical, require it to reside under an approved upload or workspace directory.
  5. Reject known-sensitive paths and filenames, including .env, private-key files, credential stores, and configuration directories.
  6. Require explicit user confirmation before uploading files outside the expected workspace.
  7. Enforce a reasonable maximum file size before opening and transmitting the file.
  8. Clearly notify the user that the selected file will be uploaded to an external service.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:130
Finding

Unrestricted API Base Can Redirect Credentials and Uploaded Files

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 39-42, 65-76, 130-151, and 190-202
Vulnerability Type: Unvalidated security-sensitive endpoint configuration
Risk Level: Medium

Complete Code Snippet

python
for key in ["SCNET_API_KEY", "SCNET_API_BASE", "SCNET_POLL_INTERVAL", "SCNET_MAX_POLL_TIME"]:
    value = os.environ.get(key)
    if value:
        config_from_env[key] = value
python
config = dict(config_from_env)
if ENV_FILE.exists():
    with open(ENV_FILE, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith('#'):
                continue
            if '=' in line:
                key, value = line.split('=', 1)
                key = key.strip()
                value = value.strip().strip('"').strip("'")
                if key not in config:
                    config[key] = value
python
api_base = config['SCNET_API_BASE']
api_key = config['SCNET_API_KEY']
url = f"{api_base}/doc/convert/task"

headers = {
    'Authorization': f'Bearer {api_key}'
}

mime_type, _ = mimetypes.guess_type(file_path)
if mime_type is None:
    mime_type = 'application/octet-stream'

try:
    with open(file_path, 'rb') as f:
        files = {
            'file': (os.path.basename(file_path), f, mime_type)
        }
        data = {
            'ocr_type': ocr_type,
        }
        response = requests.post(url, headers=headers, data=data, files=files, timeout=60)
python
api_base = config['SCNET_API_BASE']
api_key = config['SCNET_API_KEY']
url = f"{api_base}/ocrdoc/result"

headers = {
    'Authorization': f'Bearer {api_key}',
    'Content-Type': 'application/json'
}
payload = {"task_ids": task_ids}

try:
    response = requests.post(url, headers=headers, json=payload, timeout=60)

Technical Analysis

The SCNET_API_BASE s ...[truncated 2105 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove SCNET_API_BASE configurability in production and use the documented fixed endpoint.
  2. If custom endpoints are required, parse the URL and enforce an explicit allowlist of trusted hostnames.
  3. Require HTTPS and reject plaintext HTTP destinations.
  4. Reject embedded user information, unexpected ports, fragments, and malformed hostnames.
  5. Normalize and verify the hostname after parsing rather than using string-prefix checks.
  6. Use separate credentials for test or private endpoints; never send a production Scnet key to a custom server.
  7. Store configuration with restrictive filesystem permissions and prevent untrusted callers from controlling environment variables.
  8. Add a final destination check immediately before every request carrying credentials or user files.
  9. Document the permitted destinations and display the destination to the user before uploading sensitive content.
Vulnerability Patterns
  • 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (25)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.py (reported line 20)May include surrounding context.

python
# 获取技能根目录(脚本所在目录的上一级)
SKILL_ROOT = Path(__file__).parent.parent.absolute()
ENV_FILE = SKILL_ROOT / "config" / ".env"

# 重试配置
MAX_RETRIES = 3

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 71)May include surrounding context.

md
def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    config_from_env = {}
    for key in ["SCNET_API_KEY", "SCNET_API_BASE", "SCNET_POLL_INTERVAL", "SCNET_MAX_POLL_TIME"]:
        value = os.environ.get(key)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 138)May include surrounding context.

md
def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    config_from_env = {}
    for key in ["SCNET_API_KEY", "SCNET_API_BASE", "SCNET_POLL_INTERVAL", "SCNET_MAX_POLL_TIME"]:
        value = os.environ.get(key)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.py (reported line 37)May include surrounding context.

python
def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    config_from_env = {}
    for key in ["SCNET_API_KEY", "SCNET_API_BASE", "SCNET_POLL_INTERVAL", "SCNET_MAX_POLL_TIME"]:
        value = os.environ.get(key)

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · README.md (reported line 38)May include surrounding context.

md
* [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/)
* [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
* [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
* [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
* [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises capabilities that include environment variable access, local file reads, network access, and shell execution, but it does not declare any explicit tool scope or permission boundaries. This makes the skill harder to safely govern and increases the risk of over-broad execution, especially because it handles local file paths and API credentials while communicating with an external service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
74% confidence
Finding

The skill description and all user-facing invocation examples are presented only in Chinese, with no indication that users may choose another language. For organizational language/locale policy, a skill should not implicitly force a specific language unless the constraint is documented and justified or the user opts in.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The auto-trigger guidance is overly broad and says the AI may automatically invoke the skill based on description keywords, without requiring clear user confirmation or narrow activation constraints. Because the skill uploads a user-specified local file to a third-party API, ambiguous triggering can cause unintended external transmission of sensitive local content.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 · config/.env.example (reported line 6)May include surrounding context.

text
SCNET_API_KEY=your_scnet_api_key_here

# API 基础地址(一般无需修改)
SCNET_API_BASE=https://api.scnet.cn/api/llm/v1

# 轮询配置(可选)
SCNET_POLL_INTERVAL=5

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documented API supports broader capabilities than the skill metadata claims, including PDF-to-Word and image-to-Word conversions. This scope mismatch can mislead downstream agents or users into sending different data types than expected, weakening least-privilege assumptions and increasing the chance of unintended data disclosure or policy bypass.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill describes uploading local files or supplying publicly accessible file URLs to a remote third-party service without warning about privacy, retention, or data-handling implications. Users may unknowingly transmit sensitive documents externally, and public file URLs can expose internal or confidential content to the provider or anyone with access to the source URL.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The API returns temporary authorized download links, but the documentation does not treat those URLs as sensitive bearer-style secrets. Anyone who obtains such a link may be able to retrieve the converted document or presentation until expiry, which can expose potentially sensitive output files.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/main.py (reported line 59)May include surrounding context.

python
"   b) 配置文件:\n"
            f"      mkdir -p {SKILL_ROOT}/config\n"
            f"      echo 'SCNET_API_KEY=你的密钥' > {ENV_FILE}\n"
            f"      chmod 600 {ENV_FILE}\n"
            "\n配置完成后重新运行。"
        )
        sys.exit(error_msg)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/main.py (reported line 122)May include surrounding context.

python
"   b) 配置文件:\n"
            f"      mkdir -p {SKILL_ROOT}/config\n"
            f"      echo 'SCNET_API_KEY=你的密钥' > {ENV_FILE}\n"
            f"      chmod 600 {ENV_FILE}\n"
            "\n配置完成后重新运行。"
        )
        sys.exit(error_msg)

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 · SKILL.md (reported line 58)May include surrounding context.

md
)
        sys.exit(error_msg)

    config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1')

    try:
        config.setdefault('SCNET_POLL_INTERVAL', str(DEFAULT_POLL_INTERVAL))

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 · SKILL.md (reported line 118)May include surrounding context.

md
)
        sys.exit(error_msg)

    config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1')

    try:
        config.setdefault('SCNET_POLL_INTERVAL', str(DEFAULT_POLL_INTERVAL))

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 · references/api-docs.md (reported line 76)May include surrounding context.

md
)
        sys.exit(error_msg)

    config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1')

    try:
        config.setdefault('SCNET_POLL_INTERVAL', str(DEFAULT_POLL_INTERVAL))

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 · references/api-docs.md (reported line 85)May include surrounding context.

md
)
        sys.exit(error_msg)

    config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1')

    try:
        config.setdefault('SCNET_POLL_INTERVAL', str(DEFAULT_POLL_INTERVAL))

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/main.py (reported line 95)May include surrounding context.

python
)
        sys.exit(error_msg)

    config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1')

    try:
        config.setdefault('SCNET_POLL_INTERVAL', str(DEFAULT_POLL_INTERVAL))

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/main.py (reported line 202)May include surrounding context.

python
payload = {"task_ids": task_ids}

    try:
        response = requests.post(url, headers=headers, json=payload, timeout=60)
    except Exception as e:
        sys.exit(f"网络请求失败: {str(e)}")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest declares an external API credential and strongly implies the skill sends user-provided images to a remote service, but it does not clearly warn users that their content and credentials are used off-box. This creates a transparency and consent problem and can expose sensitive images or document data to an external provider without adequate notice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file contains user-facing natural language exclusively in Chinese (e.g., the title and release note) with no indication that the skill is intended only for Chinese-speaking users or that language selection is optional. Under the policy, forcing a specific language without opt-in can be a locale/language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This markdown file presents all user-facing documentation exclusively in Chinese, which can constitute a language/locale policy violation when no user opt-in or justification is provided. The content does not indicate that the skill is region-specific or that alternative language support is intentionally limited.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script's help output says ocrType can be PDF_TO_WORD, IMAGE_TO_WORD, IMAGE_TO_PPT, but SUPPORTED_TYPES only includes IMAGE_TO_PPT and the runtime rejects any other value. This is a direct contradiction between user-facing documentation and implemented behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The natural-language description forces a single language presentation without offering a language/locale option or documenting that the skill is intended only for a Chinese-speaking audience. This can violate organizational language-choice policies when users are not given an opt-in or alternative.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.