Back to skill

Security audit

jf-open-pro-device-smart-alarm

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its smart-alarm purpose, but it can send device credentials, tokens, configuration data, and alarm image metadata to an arbitrary endpoint chosen by environment variable.

Review before installing. Only run this skill with trusted environment variables, do not set JF_ENDPOINT outside the documented official jftechws.com regional hosts, and treat alarm lists and picture URLs as sensitive surveillance data. Be careful with actions that disable alarms, notifications, or schedules because they change live device monitoring.

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

Error
Location
scripts/smart_alarm.py:27
Finding

Unvalidated API Endpoint Allows Credential and Device-Token Disclosure

Content
View full analysis

Vulnerability Details

File Location: scripts/smart_alarm.py, lines 27–28, 31–43, and network request sites at lines 55–58, 119–123, 154–158, 175–179, 294–310, and 327–349
Vulnerability Type: Arbitrary destination for sensitive authenticated requests
Risk Level: High

Vulnerable Code

The destination hostname is taken directly from an environment variable without validation:

python
# API 基础地址(可通过环境变量切换)
JF_ENDPOINT = os.getenv("JF_ENDPOINT", "api-cn.jftechws.com")
JF_BASE_URL = f"https://{JF_ENDPOINT}/gwp/v3"

Every request includes authentication-related headers derived from sensitive application credentials:

python
def get_headers(uuid: str, app_key: str, app_secret: str, move_card: int) -> Dict[str, str]:
    """生成请求头(包含签名和时间戳)"""
    time_millis = get_time_millis()
    signature = generate_signature(uuid, app_key, app_secret, time_millis, move_card)
    
    return {
        "Content-Type": "application/json; charset=UTF-8",
        "uuid": uuid,
        "appKey": app_key,
        "timeMillis": time_millis,
        "signature": signature,
        "X-Request-Id": os.urandom(16).hex()
    }

Device tokens are included in URLs sent to the selected host. For example:

python
def get_device_ability(device_token: str, uuid: str, app_key: str,
                       app_secret: str, move_card: int) -> Dict[str, Any]:
    """
    获取设备能力集
    
    Returns:
        能力集数据
    """
    url = f"{JF_BASE_URL}/rtc/device/getability/{device_token}"
    headers = get_headers(uuid, app_key, app_secret, move_card)
    
    response = requests.post(url, headers=headers, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:
        raise RuntimeError(f"获取能力集失败:{result.get('msg', '未知错误')}")
    
    return result.get("data", {})

Alarm query details are also sent to the selected destination:

python
def get_ala
...[truncated 4341 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the raw JF_ENDPOINT setting with a constrained region selector and an internal mapping:

    python
    OFFICIAL_ENDPOINTS = {
        "CN": "api-cn.jftechws.com",
        "AS": "api-as.jftechws.com",
        "EU": "api-eu.jftechws.com",
        "NA": "api-na.jftechws.com",
        "SA": "api-sa.jftechws.com",
        "RU": "api-ru.jftechws.com",
        "AF": "api-af.jftechws.com",
        "OC": "api-oc.jftechws.com",
    }
    
    region = os.getenv("JF_REGION", "CN").upper()
    if region not in OFFICIAL_ENDPOINTS:
        raise RuntimeError("Unsupported JF API region")
    
    JF_BASE_URL = f"https://{OFFICIAL_ENDPOINTS[region]}/gwp/v3"
    
  2. If hostname configuration must be retained, compare the parsed hostname against an exact allowlist. Reject subdomains, user-information components, explicit ports, paths, query strings, fragments, IP literals, and redirects to unapproved hosts.

  3. Configure requests not to follow redirects automatically for authenticated calls, or validate every redirect destination before forwarding sensitive headers:

    python
    response = requests.post(
        url,
        headers=headers,
        json=body,
        timeout=30,
        allow_redirects=False,
    )
    
  4. Where supported by the API, move the device token out of the URL path and into an authorization header. URLs are more likely to appear in proxy, server, monitoring, and exception logs.

  5. Use narrowly scoped, short-lived device tokens and rotate a token immediately if it may have been transmitted to an untrusted endpoint.

  6. Add tests confirming that unsupported regions, arbitrary domains, deceptive suffixes such as api-cn.jftechws.com.attacker.example, URL user information, IP addresses, and nonstandard ports are rejected before any request is made.

  7. Document the exact permitted remote hosts and ensure deployment policy prevents untrusted users or wrappers from alteri ...[truncated 42 chars]

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

Tainted flow: 'url' from os.getenv (line 328, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The request destination is derived from the JF_ENDPOINT environment variable and then used to send signed API requests containing identifiers and authentication material in headers. If an attacker can influence the process environment, the script can be redirected to an attacker-controlled host, causing credential exfiltration and unauthorized transmission of device metadata.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 58)May include surrounding context.

python
headers = get_headers(uuid, app_key, app_secret, move_card)
    headers["DeviceSn"] = device_sn
    
    response = requests.get(url, headers=headers, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

Tainted flow: 'url' from os.getenv (line 328, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
99% confidence
Finding

This POST sends sensitive material, including accessToken and signed authentication headers, to a URL whose host is ultimately controlled by JF_ENDPOINT from the environment. In a skill context that may run with ambient secrets set as environment variables, this creates a practical SSRF-style exfiltration path to attacker infrastructure.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 94)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 328, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The device ability request transmits signed headers to a host built from an environment-controlled endpoint. Although the path contains a device token rather than a request body, redirecting the request can still leak the device token and request authentication metadata to an untrusted server.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 123)May include surrounding context.

python
url = f"{JF_BASE_URL}/rtc/device/getability/{device_token}"
    headers = get_headers(uuid, app_key, app_secret, move_card)
    
    response = requests.post(url, headers=headers, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

Tainted flow: 'url' from os.getenv (line 328, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The motion-detect configuration request sends device configuration data and authentication headers to a URL derived from an environment variable. If the endpoint is tampered with, an attacker can harvest secrets and potentially capture or influence sensitive device configuration operations.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 158)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 328, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
98% confidence
Finding

This set-config call performs a privileged device configuration update while using a destination host derived from the environment. A hostile endpoint can receive signed headers and full configuration payloads, exposing both credentials and operational security settings for the device.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 179)May include surrounding context.

python
"Detect.MotionDetect": config
    }
    
    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 328, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

Alarm list queries include sensitive surveillance metadata such as event times and identifiers, and are sent to a host controlled by JF_ENDPOINT. In this smart-alarm skill, such data is privacy-sensitive, so endpoint tampering materially increases the risk of surveillance data leakage.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 310)May include surrounding context.

python
if alarm_event:
        body["alarmEvent"] = alarm_event
    
    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 328, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The alarm picture retrieval request can disclose URLs and metadata for surveillance images to an attacker-controlled endpoint if JF_ENDPOINT is manipulated. Given this skill handles alarm images, the context makes endpoint redirection especially dangerous because it can expose highly sensitive physical-security information.

Content

Scanner excerpt · scripts/smart_alarm.py (reported line 349)May include surrounding context.

python
if events:
        body["events"] = events
    
    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.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill documents use of environment variables and network-accessing scripts/APIs but does not declare any tool scope such as permissions or allowed-tools. This creates an authorization gap: an agent or reviewer cannot easily tell that the skill needs secret access and outbound network capability, increasing the chance of over-privileged execution or accidental secret exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill supports operations that can enable/disable alarms and alter notification schedules, but it does not clearly warn users that these actions change real device behavior. This can lead to unsafe or unintended security posture changes, such as disabling detection or suppressing mobile alerts without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill allows retrieval of cloud-stored alarm messages and image URLs, which may contain sensitive surveillance data, but it does not include a privacy warning or handling guidance. Users may expose personal or location-sensitive images and event histories without understanding retention, sharing, or access implications.

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/smart_alarm.py (reported line 94)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/smart_alarm.py (reported line 158)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/smart_alarm.py (reported line 179)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/smart_alarm.py (reported line 310)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/smart_alarm.py (reported line 349)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:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script prints alarm image URLs and detailed alarm metadata directly to stdout without redaction, confirmation, or privacy warning. In shared terminals, logs, CI pipelines, or agent platforms that capture output, this can leak sensitive surveillance data beyond the intended operator.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill metadata, description, and trigger phrases are entirely in Chinese, with no indication that users can choose another language or that the locale restriction is required. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code file's natural-language content is entirely in Chinese, including the module docstring and function comments, with no indication that the skill is region-specific or that users may choose another language. Under the language/locale policy, forcing a specific language without opt-in can be a policy violation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

函数 generate_signature 及其下游 change 的参数文档都将 move_card 描述为整数/移动取模基数,但测试代码在 L174 将其赋值为字符串,并在 L176 直接传入。该示例与代码文档宣称的调用方式相矛盾,若按示例执行还会在取模运算处产生类型错误。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring presents the skill name and supported functions only in Chinese, and the command-line help strings throughout the file are likewise fixed to a single language. This enforces a specific language experience without user opt-in or justification that the skill is intended solely for a Chinese-language environment.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module docstring claims the skill supports '设备状态检查' and '设备登录', but the exposed actions in the argument parser only include get-ability, get-config, set-switch, set-message-notify, set-time-section, get-alarm-list, and get-alarm-pic. Although a get_device_status helper exists, it is never wired into the command interface, and there is no implemented device login action at all.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The docstring for get_device_token documents an accessToken obtained from '杰峰 AMS 用户系统登录返回', implying this skill handles or at least includes that login flow. In this file, there is no AMS login implementation and the function itself only consumes a passed token, so the documentation overstates what the code actually does.

Content

No source excerpt is available for this finding.