Back to skill

Security audit

jf-open-pro-capture

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to perform the advertised camera capture task, but it handles camera credentials, API endpoints, and downloaded images with weak scoping that could expose tokens or write files unexpectedly.

Review before installing. Use only the listed JFTech API domains for JF_ENDPOINT, avoid passing real device passwords on the command line, treat captured images and URLs as sensitive, and avoid --download on shared or privileged machines until endpoint, URL, size, and filename validation are improved.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/capture.py:30
Finding

Authenticated API Requests Can Be Redirected to an Arbitrary Host

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/capture.py:120
Finding

Unvalidated Image URL Enables Server-Side Request Forgery and Unbounded Downloads

Content
View full analysis
bool: """ Download an image locally. Args: image_url: Image URL output_path: Destination path Returns: Whether the operation succeeded """ try: resp = requests.get(image_url, timeout=30) if resp.status_code == 200: with open(output_path, 'wb') as f: f.write(resp.content) return True return False except Exception: return False ``` ### Technical Analysis The image URL is taken from the capture API response and passed directly to `requests.get`. The code does not validate: - URL scheme - Destination hostname - Resolved IP address - Redirect destinations - Whether the address is loopback, private, link-local, or otherwise reserved - Response content type - Response size The `requests` library follows redirects by default. Consequently, even a URL whose initial hostname appears trusted can redirect to an internal service. The complete response body is also buffered in memory through `resp.content` and then written without a size limit. This creates a resource-exhaustion risk in addition to SSRF. ### Attack Path 1. An attacker compromises, impersonates, or redirects the configured API endpoint, or otherwise controls the returned `image` field. 2. The capture response supplies an internal URL, for example a loopback service, private network service, or cloud metadata endpoint. 3. The user invokes capture with the `--download` option. 4. `download_image` sends a GET request from the victim host to the attacker-selected address. 5. If the endpoint returns HTTP 200, its response is stored in the capture output file. 6. Alternatively, the attacker returns a very large res ...[truncated 847 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/capture.py:390
Finding

Unsanitized Device Serial Number Can Escape the Capture Output Directory

Content
View full analysis
= 1: device = { 'sn': parts[0].strip(), 'name': parts[1].strip() if len(parts) > 1 else parts[0].strip() } devices.append(device) ``` ### Technical Analysis The batch capture flow incorporates `sn` directly into a filename. It does not reject path separators, traversal components such as `..`, absolute paths, or platform-specific filename syntax. `os.path.join` does not guarantee containment. A serial number containing traversal components can cause the resolved destination to leave `output_dir`. The subsequent `open(output_path, 'wb')` operation creates or truncates the selected file. Successful exploitation through the batch workflow also requires the serial number to receive a corresponding token and capture response. This condition can arise if the API accepts or reflects the crafted identifier, or if the API destination or response is attacker-controlled. ### Attack Path 1. An attacker supplies or modifies the batch devices file. 2. The file contains a crafted serial number with path traversal components. 3. The token API returns a corresponding token for that identifier, or an attacker-controlled API response supplies one. 4. Capture succeeds and returns an image URL. 5. The user runs batch capture with `--download`. 6. The crafted serial number is concatenated into `f ...[truncated 761 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/capture.py:471
Finding

Capture Workflow Requires and Collects an Unused Device Password

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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
Findings (15)

Tainted flow: 'url' from os.getenv (line 92, 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/capture.py (reported line 65)May include surrounding context.

python
"accessToken": access_token
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

Tainted flow: 'url' from os.getenv (line 92, 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/capture.py (reported line 103)May include surrounding context.

python
"accessToken": access_token
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

声明描述的核心能力是设备抓图相关业务功能,但代码块实际仅是底层加密辅助模块,负责生成时间戳和请求签名。虽然这种签名工具可能是抓图 API 调用的支持性实现细节,但就当前提供的代码块本身而言,其主要行为与声明的主要用途明显不一致。根据评估标准,这属于“实际主要目的与声明不同”,应判定为描述与行为不匹配。

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `SKILL.md` | 技能文档 |

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill documentation declares network, environment-variable, and file-based behavior but does not define any explicit tool scope or allowed-tools boundary. In agent environments, this can lead to overbroad execution privileges, making it easier for the skill to access secrets, read local files, or perform network calls beyond the user's expectation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation promotes optional local download of captured device images without warning that these images may contain sensitive surveillance content and will persist on disk. In the context of camera capture, silent local storage increases privacy, retention, and unauthorized-access risk, especially on shared hosts or poorly secured workspaces.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation instructs users to provide sensitive secrets including app secrets, device passwords, and access tokens, but does not clearly warn against logging, hardcoding, or exposing them in shell history and shared environments. Because this skill interfaces with device capture APIs, leaked credentials could enable unauthorized image capture, token abuse, or broader account compromise.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains user-facing natural-language text entirely in Chinese, including the module description and later CLI output/help strings, with no indication that other languages are supported. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

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

python
"accessToken": access_token
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

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

python
"accessToken": access_token
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

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

Medium
Category
Data Flow
Confidence
88% confidence
Finding

The code downloads from image_url returned by a remote API without validating the destination host, scheme, or content type. If the upstream service is compromised or spoofed, this can turn the skill into an SSRF-style fetcher or cause it to retrieve unexpected internal or malicious content and write it to disk.

Content

Scanner excerpt · scripts/capture.py (reported line 131)May include surrounding context.

python
是否成功
    """
    try:
        resp = requests.get(image_url, timeout=30)
        if resp.status_code == 200:
            with open(output_path, 'wb') as f:
                f.write(resp.content)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

L518-L519 的校验提示明确声明 capture-auto 需要设备密码,暗示该操作会使用用户名/密码参与认证或抓图流程。但在 L231-L313 的 capture_auto_action 以及其调用链中,代码只通过开放平台凭证获取 token 并抓图,未读取或使用 args.password。这属于文案/参数说明与实际行为相矛盾,而非单纯信息不完整。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code file contains user-facing natural-language documentation exclusively in Chinese, including the module docstring and function comments. Under the stated policy, forcing a specific language without offering the user a language/locale choice can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script prints a user-facing message only in Chinese at runtime, with no option to choose another language or indication that the tool is region-specific. This can violate language/locale policy because the skill effectively forces one language on all users.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The inline test block sets move_card = "your-movecard-here" and immediately passes it to generate_signature, while the function signature declares move_card: int and change() uses i % move_card. This is an active contradiction between the example/documentation intent and what the code can actually execute.

Content

No source excerpt is available for this finding.