Back to skill

Security audit

海康云眸设备基础管理

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to do the device-management work it claims, but it handles powerful cloud-device credentials and destructive actions with weak endpoint, cache, and confirmation safeguards.

Install only if you trust the publisher and will run it with tightly scoped Hik-Cloud credentials. Avoid custom `HIK_OPEN_BASE_URL` or `--base-url` values unless you fully control and trust the endpoint, protect the token cache path, and manually confirm delete or reboot requests before invoking them.

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/hik_open_device_management.py:107
Finding
OAuth credentials and bearer tokens can be transmitted to an arbitrary or plaintext endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/hik_open_device_management.py:107-120`, `scripts/hik_open_device_management.py:187-218`, `scripts/hik_open_device_management.py:261-268`, and `scripts/hik_open_device_management.py:393` **Vulnerability Type**: Unrestricted credential destination and missing HTTPS enforcement **Risk Level**: High ### Vulnerable Code ```python def normalize_base_url(base_url: str) -> str: normalized = base_url.strip() if not normalized: raise ApiError("base URL must not be empty") return normalized.rstrip("/") def resolve_base_url(explicit_base_url: str | None) -> str: if explicit_base_url: return normalize_base_url(explicit_base_url) env_base_url = os.getenv(BASE_URL_ENV_VAR) if env_base_url: return normalize_base_url(env_base_url) return DEFAULT_BASE_URL ``` ```python def fetch_access_token( base_url: str, client_id: str, client_secret: str, timeout: float, ) -> dict[str, Any]: status, payload = http_json_request( method="POST", url=base_url.rstrip("/") + TOKEN_PATH, headers=None, timeout=timeout, form_body={ "client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials", "scope": "app", }, ) if status != 200 or "access_token" not in payload: error_code, error_message = summarize_error_payload(payload) raise ApiError( "failed to fetch access token: " f"http={status}, code={error_code}, message={error_message}" ) expires_in = int(payload.get("expires_in", 0)) return { "access_token": payload["access_token"], "expires_in": expires_in, "expires_at": time.time() + max(expires_in, 0), "token_type": payload.get("token_type", "bearer"), } ``` ```python token, refreshed = resolve_access_token(base_url, timeout, cache_file, expli ...[truncated 2826 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the URL with `urllib.parse.urlsplit` and reject malformed URLs. 2. Require `https` for all token and API requests. If local development requires HTTP, place it behind a clearly named, disabled-by-default development override that refuses production credentials. 3. Allowlist `api2.hik-cloud.com` by default. 4. Require explicit administrator configuration for additional trusted staging or private endpoints. 5. Reject URLs containing user information, fragments, unexpected ports, or ambiguous host representations. 6. Disable redirects for requests containing credentials, or validate every redirect target against the same scheme and hostname policy before following it. 7. Bind cached tokens to the normalized issuer origin and do not reuse a token after the base URL changes. 8. Add tests confirming rejection of `http://`, unapproved hosts, embedded credentials, and unsafe redirects. 9. Prefer separate credentials with reduced privileges for staging and custom endpoint configurations. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hik_open_device_management.py:132
Finding
Bearer tokens are cached in plaintext without enforced restrictive file permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/hik_open_device_management.py:21`, `scripts/hik_open_device_management.py:123-134`, and `scripts/hik_open_device_management.py:245-246` **Vulnerability Type**: Insecure local storage of authentication tokens **Risk Level**: Medium ### Vulnerable Code ```python DEFAULT_TOKEN_CACHE = Path.home() / ".cache" / "hik_open" / "token.json" ``` ```python def load_token_cache(cache_file: Path) -> dict[str, Any] | None: if not cache_file.exists(): return None try: return json.loads(cache_file.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): return None def save_token_cache(cache_file: Path, payload: dict[str, Any]) -> None: cache_file.parent.mkdir(parents=True, exist_ok=True) cache_file.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") ``` ```python token_payload = fetch_access_token(base_url, client_id, client_secret, timeout) save_token_cache(cache_file, token_payload) ``` ### Technical Analysis The cached payload contains the plaintext bearer token and expiration information. The cache is written with `Path.write_text`, which does not explicitly establish mode `0600`, validate file ownership, reject symbolic links, or guarantee atomic secure creation. Actual permissions depend on the process umask and any pre-existing file. Under a common umask of `022`, a newly created regular file may be readable by users other than its owner. If the file already exists, its previous permissions are retained. The implementation also accepts a caller-controlled `--token-cache-file`, which can point to a shared, permissive, or otherwise unsafe location. The code checks existence before reading and directly follows the selected path for both reads and writes. It does not verify that the file and parent directory are owned by the current user or that they are not symbolic links. Exploitation through a symbolic link requires ...[truncated 1412 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the cache directory with owner-only permissions (`0700`). 2. Create the cache file with owner read/write permissions (`0600`) using low-level flags such as `O_CREAT`, `O_EXCL`, and, where available, `O_NOFOLLOW`. 3. Verify that the cache file is a regular file owned by the current user before reading or replacing it. 4. Reject symbolic links and cache paths located in directories not controlled by the current user. 5. Correct overly permissive permissions on an existing cache before reading it, or refuse to use the file and report a clear security error. 6. Write to a securely created temporary file in the same protected directory, flush it, and atomically replace the cache. 7. Consider storing bearer tokens in an operating-system credential manager instead of a plaintext JSON file. 8. Validate custom `--token-cache-file` paths and clearly document their security requirements. 9. Add tests asserting owner-only permissions, symlink rejection, ownership validation, and secure behavior with pre-existing permissive files. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
声明描述的是一个可操作海康云眸设备管理接口的技能,而实际给出的代码块仅包含测试用例,作用是验证技能说明文档和参考文档是否写入了指定内容。这种行为与声明的主要用途存在明显偏差。虽然测试中提到了 skillKey、环境变量、token 隐藏和状态字段语义,但这些只是文档约束检查,不构成实际的设备管理实现。因此该代码块与声明用途不匹配。

Credential Access

High
Category
Privilege Escalation
Content
通用参数:

- `--base-url`:显式指定接口域名,优先级高于环境变量
- `--access-token`:显式指定 access token
- `--timeout`:请求超时秒数,默认 `20`
- `--token-cache-file`:token 缓存文件,默认 `~/.cache/hik_open/token.json`
- `--format`:`text` 或 `json`
Confidence
83% confidence
Finding
The skill explicitly supports passing an access token via command-line argument, and command-line secrets are commonly exposed through process listings, shell history, logs, and debugging output. In this context the token grants access to cloud device-management operations, so exposure could let an attacker query, modify, delete, or reboot managed devices.

Credential Access

High
Category
Privilege Escalation
Content
if status != 200 or "access_token" not in payload:
        error_code, error_message = summarize_error_payload(payload)
        raise ApiError(
            "failed to fetch access token: "
            f"http={status}, code={error_code}, message={error_message}"
        )
    expires_in = int(payload.get("expires_in", 0))
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares capabilities that involve environment variables, file access, token caching, and outbound network calls, but it does not constrain them with an explicit tool scope such as permissions or allowed-tools. In an agent setting, missing scope boundaries increases the chance of unintended secret access, broader filesystem interaction, or unrestricted network use beyond the device-management purpose.

Session Persistence

Medium
Category
Rogue Agent
Content
注册设备:

```bash
python3 {baseDir}/scripts/hik_open_device_management.py create \
  --device-serial E05426006 \
  --group-no fsdfe \
  --validate-code ADSEFE
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
注册设备:

```bash
python3 {baseDir}/scripts/hik_open_device_management.py create \
  --device-serial E05426006 \
  --group-no fsdfe \
  --validate-code ADSEFE
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Vague Triggers

Medium
Confidence
86% confidence
Finding
The default prompt broadly activates the skill for generic device-management tasks such as create, delete, query, and reboot without narrowing scope by tenant, device ownership, confirmation requirements, or explicit user intent. In a skill that can perform destructive and operationally sensitive actions on cloud-connected devices, overly broad activation increases the chance of accidental invocation, unauthorized administrative actions, or harmful reboot/deletion flows being triggered from ambiguous requests.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This markdown file documents use of `client_secret`, access tokens, and environment variables for authentication, and earlier states the skill will automatically fetch, cache, refresh, and inject bearer tokens. It does not include any warning about handling secrets, transmitting credentials to a remote platform, or the privacy/security impact of automatic authentication behavior.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest claims automatic access_token refresh, but on a 401 the code retries by calling resolve_access_token() without forcing a refresh. If a cached token is still considered valid by local expiry logic but has been revoked or invalidated server-side, the same bad token can be reused and the operation fails, which can break expected device-management actions and create reliability/security-control gaps.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The delete command issues a device deletion API request, but the code provides no confirmation prompt, warning message, or explanatory disclosure before performing the operation. Because deletion is destructive and potentially irreversible, users should be explicitly warned when invoking this command.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The reboot command sends a system reboot request to a device without any visible disclosure, confirmation, or warning in the code path. Rebooting a device can interrupt service and affect system availability, so users should be alerted before the action is executed.

Natural-Language Policy Violations

Medium
Confidence
83% confidence
Finding
This test requires specific Chinese phrases to appear in the skill documentation, which effectively constrains the skill's natural-language output or documentation language. Because no user opt-in or region-specific justification is present in this file, this may violate the language/locale policy requirement.

Natural-Language Policy Violations

Low
Confidence
71% confidence
Finding
The natural-language metadata presents the skill name and description in Chinese while the default prompt is fixed in English, with no indication that the user can choose their preferred language. This may impose a language behavior inconsistent with user expectations and lacks an explicit opt-in or documented locale policy.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
该 markdown 文件的自然语言说明全文均为中文,未见提供其他语言选项、用户选择机制,或说明这是仅适用于中文用户/区域的文档。根据语言/locale 政策,这可能构成未经过用户选择的语言强制。

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
return

    for method_name in ("SetConsoleOutputCP", "SetConsoleCP"):
        method = getattr(kernel32, method_name, None)
        if not callable(method):
            continue
        try:
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_hik_open_device_management.py:16