Back to skill

Security audit

jf-open-pro-device-osd

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated device OSD purpose, but it can send device tokens and signed API metadata to any hostname placed in JF_ENDPOINT.

Review this before installing. Only use it with trusted JF credentials, set JF_ENDPOINT to one of the documented JF regional API hosts, and avoid running state-changing actions unless you have confirmed the target device, channel, and title. Rotate the device token if it may have been used with an untrusted endpoint.

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

Error
Location
scripts/osd_config.py:25
Finding

Unrestricted API Endpoint Can Receive Device Tokens and Authentication Metadata

Content
View full analysis

Vulnerability Details

File Location: scripts/osd_config.py, lines 25-26, 50-51, 73, 91-92, and 114
Vulnerability Type: Unrestricted credential-bearing network destination
Risk Level: High

Vulnerable Code

python
# API base address (switchable through an environment variable)
JF_ENDPOINT = os.getenv("JF_ENDPOINT", "api-cn.jftechws.com")
JF_BASE_URL = f"https://{JF_ENDPOINT}/gwp/v3"
python
def get_osd_config(device_token: str, uuid: str, app_key: str,
                   app_secret: str, move_card: int,
                   config_type: str = "single",
                   channel: int = 0) -> Dict[str, Any]:
    """
    Get OSD configuration

    API: POST /gwp/v3/rtc/device/getconfig/{deviceToken}
    """
    url = f"{JF_BASE_URL}/rtc/device/getconfig/{device_token}"
    headers = get_headers(uuid, app_key, app_secret, move_card)

    name_map = {
        "single": "AVEnc.VideoWidget",
        "multi": "AVEnc.VideoOSD"
    }

    body = {
        "Name": name_map.get(config_type, "AVEnc.VideoWidget")
    }

    if channel is not None:
        body["Channel"] = str(channel)

    response = requests.post(url, headers=headers, json=body, timeout=30)
python
def set_osd_config(device_token: str, uuid: str, app_key: str,
                   app_secret: str, move_card: int,
                   config: Dict[str, Any],
                   config_type: str = "single",
                   channel: int = 0) -> Dict[str, Any]:
    """
    Set OSD configuration

    API: POST /gwp/v3/rtc/device/setconfig/{deviceToken}
    """
    url = f"{JF_BASE_URL}/rtc/device/setconfig/{device_token}"
    headers = get_headers(uuid, app_key, app_secret, move_card)

    name_map = {
        "single": "AVEnc.VideoWidget",
        "multi": "AVEnc.VideoOSD"
    }

    body = {
        "Name": name_map.get(config_type, "AVEnc.VideoWidget")
    }

    if config_ty
...[truncated 2937 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the unrestricted hostname with an enumerated region option such as CN, AS, EU, or NA.
  2. Map each region internally to one of the four documented API hosts.
  3. If JF_ENDPOINT must remain configurable, parse it as a hostname and enforce an exact allowlist:
    • api-cn.jftechws.com
    • api-as.jftechws.com
    • api-eu.jftechws.com
    • api-na.jftechws.com
  4. Reject values containing a scheme, path, query string, fragment, user information, unexpected port, trailing-dot variant, or unapproved Unicode hostname.
  5. Disable automatic redirects with allow_redirects=False. If redirects are operationally necessary, validate every redirect target against the same exact allowlist before resending sensitive data.
  6. Avoid placing access tokens in URL paths if the upstream API supports an authorization header or another protected request field.
  7. Use short-lived, narrowly scoped device tokens and rotate any token suspected of having been sent to an unauthorized endpoint.
  8. Add automated tests confirming that arbitrary hosts, alternate ports, malformed hostnames, and external redirects are rejected.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/crypto.py:91
Finding

Unvalidated Signing Parameter Causes a Denial of Service

Content
View full analysis

Vulnerability Details

File Location: scripts/osd_config.py, lines 302-303; scripts/crypto.py, line 91
Vulnerability Type: Improper numeric input validation
Risk Level: Low

Vulnerable Code

python
parser.add_argument("--move-card", type=int, default=os.getenv("JF_MOVE_CARD", "2"),
                    help="Move-card identifier")
python
def change(encrypt_str: str, move_card: int) -> list:
    """
    Simple shifting algorithm implemented according to the Java version.

    Args:
        encrypt_str: Input string
        move_card: Move-card identifier

    Returns:
        Shifted byte array
    """
    try:
        encrypt_byte = list(encrypt_str.encode('iso-8859-1'))
    except UnicodeEncodeError:
        encrypt_byte = str_to_bytes(encrypt_str)

    encrypt_length = len(encrypt_byte)

    for i in range(encrypt_length):
        if (i % move_card) > ((encrypt_length - i) % move_card):
            temp = encrypt_byte[i]
        else:
            temp = encrypt_byte[encrypt_length - (i + 1)]

        encrypt_byte[i] = encrypt_byte[encrypt_length - (i + 1)]
        encrypt_byte[encrypt_length - (i + 1)] = temp

    return encrypt_byte

Technical Analysis

The --move-card argument accepts any integer and is also configurable through JF_MOVE_CARD. No range check is performed before the value reaches change().

When move_card is zero, both modulo operations attempt division by zero and raise an uncaught ZeroDivisionError. Negative values do not raise the same exception but can produce unintended signing behavior inconsistent with the documented platform algorithm.

The action handlers only catch RuntimeError, so the arithmetic exception escapes and terminates the process. This is a local availability and robustness flaw rather than a confidentiality or privilege-escalation issue.

Attack Path

  1. Set the environment variable `JF_MOVE_ ...[truncated 865 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate move_card before signature generation and reject values below one.

  2. If the platform protocol supports only the documented value of 2, remove user configurability or require that exact value.

  3. Implement argument validation through a dedicated parser function, for example:

    python
    def positive_int(value: str) -> int:
        parsed = int(value)
        if parsed < 1:
            raise argparse.ArgumentTypeError("move-card must be at least 1")
        return parsed
    
  4. Apply the validator to both command-line and environment-derived values.

  5. Add defensive validation inside change() so direct callers cannot bypass CLI validation.

  6. Catch expected validation failures and return a concise error without exposing a traceback.

  7. Add tests for zero, negative numbers, nonnumeric values, and the platform's supported upper bounds.

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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (13)

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

python
if channel is not None:
        body["Channel"] = str(channel)
    
    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 91, 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/osd_config.py (reported line 111)May include surrounding context.

python
if channel is not None:
        body["Channel"] = str(channel)
    
    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
98% confidence
Finding

声明描述的是设备实时画面的 OSD 水印设置能力,但提供的代码块完全聚焦于 OpenAPI 签名算法实现。它生成时间戳、构造字节数组、执行移位和合并,并最终计算 MD5 签名。这类功能可能是调用某些设备 API 的底层辅助模块,但就当前代码本身而言,并没有任何与 OSD、水印、通道标题、时间标题或隐私区域配置相关的行为。因此代码实际用途与声明的主要目的明显不一致,应判定为不匹配。

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 246)May include surrounding context.

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

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill documents use of environment variables and outbound API calls but does not declare any explicit tool scope or permission boundaries. In an agent environment, this can lead to over-broad execution authority, making it easier for the skill to access secrets and perform network actions without clear user visibility or policy enforcement.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The trigger phrases are broad and ambiguous, especially around privacy-region and video-watermark requests, which increases the chance that the skill is invoked in situations the user did not intend. Because the skill can alter device display and masking behavior, overly broad triggers can cause accidental configuration changes with operational or privacy consequences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document requires highly sensitive secrets and device tokens but does not warn about secure storage, least-privilege handling, rotation, or log redaction. In an agent-assisted environment, this omission materially increases the risk of credential exposure, unauthorized device access, and abuse of the associated platform account.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code file contains natural-language strings and comments that present the tool exclusively in Chinese, including the module docstring and later user-facing output. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The printed notice is shown only in Chinese and does not provide any language selection or indicate that the tool is restricted to Chinese-speaking users. That creates a language policy issue for a general-purpose skill file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This file contains natural-language descriptions, help text, and status messages exclusively in Chinese, beginning with the module docstring and continuing throughout the CLI interface. Under the policy, forcing a specific language without offering a choice or documenting a justified locale restriction is a natural-language policy violation.

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

python
if channel is not None:
        body["Channel"] = str(channel)
    
    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/osd_config.py (reported line 111)May include surrounding context.

python
if channel is not None:
        body["Channel"] = str(channel)
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

该技能支持设置通道标题、时间标题和隐私区域,属于会直接改变设备画面叠加与显示效果的写操作。文档虽介绍了功能,但缺少显式用户警示,未提前说明这些操作会即时影响设备预览/录像画面以及可能覆盖现有配置。

Content

No source excerpt is available for this finding.