Back to skill

Security audit

海康云眸视频录像管理

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated Hik-Cloud video recording purpose, but it handles powerful cloud credentials and destructive remote actions with under-scoped destination controls and weak token-storage safeguards.

Review before installing in any real Hik-Cloud environment. Use only a trusted HTTPS Hik-Cloud base URL, avoid passing bearer tokens on the command line, protect or disable the token cache on shared systems, and require explicit human confirmation before delete, stop, flow-limit, upload, download-link, or clipping actions against production projects or video files.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/hik_open_video_recording.py:125
Finding

Credentials and bearer tokens can be transmitted to an arbitrary destination

Content
View full analysis
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", }, ) ``` ```python token, refreshed = resolve_access_token(base_url, timeout, cache_file, explicit_token) headers = {"Authorization": f"Bearer {token}"} status, payload = http_json_request( method=spec.method, url=spec.build_url(base_url), headers=headers, timeout=timeout, json_body=spec.json_body, ) ``` ```python parser.add_argument("--base-url", default=None) parser.add_argument("--access-token", default=None) parser.add_argument("--timeout", type=float, default=DEFAULT_TIMEOUT) parser.add_argument("--token-cache-file", default=str(DEFAULT_TOKEN_CACHE)) parser.add_argument("--format", choices=("text", "json"), default="text") ``` ### Technical Analysis The Skill must transmit crede ...[truncated 3252 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hik_open_video_recording.py:137
Finding

OAuth access tokens are persistently cached in plaintext without enforced restrictive permissions

Content
View full analysis
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 cache_payload = load_token_cache(cache_file) if cache_payload and token_still_valid(cache_payload): return str(cache_payload["access_token"]), False client_id = os.getenv("HIK_OPEN_CLIENT_ID") client_secret = os.getenv("HIK_OPEN_CLIENT_SECRET") if not client_id or not client_secret: raise ApiError( "missing credentials: set HIK_OPEN_CLIENT_ID and HIK_OPEN_CLIENT_SECRET, " "or pass --access-token" ) token_payload = fetch_access_token(base_url, client_id, client_secret, timeout) save_token_cache(cache_file, token_payload) return str(token_payload["access_token"]), True ``` ### Technical Analysis The script writes the OAuth bearer token, expiry information, and token type to a persistent JSON file. `Path.write_text` uses permissions determined by the process umask when creating a file and does not enforce owner-only access. Existing cache files are not checked or tightened. The implementation also allows `--token-cache-file` to designate an arbitrary path. It does not verify file ownership, reject symbolic links, ensure that the parent directory belongs to the current user, or perform an atomic o ...[truncated 1698 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hik_open_video_recording.py:555
Finding

Bearer tokens can be exposed through command-line arguments

Content
View full analysis
None: parser.add_argument("--base-url", default=None) parser.add_argument("--access-token", default=None) parser.add_argument("--timeout", type=float, default=DEFAULT_TIMEOUT) parser.add_argument("--token-cache-file", default=str(DEFAULT_TOKEN_CACHE)) parser.add_argument("--format", choices=("text", "json"), default="text") ``` The documented token precedence explicitly permits this source: ```text 2. token source priority: - --access-token - HIK_OPEN_ACCESS_TOKEN - token cache - HIK_OPEN_CLIENT_ID + HIK_OPEN_CLIENT_SECRET ``` ### Technical Analysis The `--access-token` option places a reusable bearer token directly in the process argument vector. Depending on the operating system and execution environment, command-line arguments may be visible through: - Process inspection tools and process metadata. - Shell history. - Job runners and audit systems. - Agent tool-call transcripts. - Debug logs and command telemetry. - Error reports that capture invoked commands. An environment-variable alternative exists, but the CLI argument has the highest documented precedence and is presented as a supported routine input. The token is not printed by the Python implementation itself, but exposure can occur before or outside the script. ### Attack Path 1. A user or Agent invokes the Skill with `--access-token `. 2. The complete command line is recorded in shell history, Agent execution traces, process accounting, an orchestration log, or an observable process table. 3. A local user or log reader obtains the token. 4. The attacker submits the token in an `Authorization: Bearer` header to t ...[truncated 671 chars]
Remediation
View remediation
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明描述的是一个面向海康云眸开放平台的视频云录制操作技能,但实际代码块只是测试/校验文档内容是否包含特定字符串和说明,属于技能契约或文档完整性测试。其主要目的与声明的业务能力明显不一致。虽然测试内容提到了 token、环境变量、枚举等,但这些只是验证文档声明,不构成实际功能实现。因此这是显著的描述与行为不匹配。

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Documenting a direct --access-token parameter and token cache behavior creates a credential-handling surface that can lead to token exposure through command history, logs, process listings, or insecure local storage. In this skill context, the danger is increased because the skill explicitly works with bearer tokens for cloud video operations and also mentions structured outputs and caching.

Content

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

md
通用参数:

- `--base-url`:显式指定接口域名,优先级高于环境变量
- `--access-token`:显式指定 access token
- `--timeout`:请求超时秒数,默认 `20`
- `--token-cache-file`:token 缓存文件,默认 `~/.cache/hik_open/token.json`
- `--format`:`text` 或 `json`

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/hik_open_video_recording.py (reported line 222)May include surrounding context.

python
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))

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises capabilities that require network access, environment variable access, and file read/write for token caching, but it declares no explicit tool scope or permission boundaries. In an agent setting, this weakens least-privilege controls and makes it easier for the skill to access credentials, persist data, or call external endpoints without transparent authorization constraints.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

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

创建项目:

bash
python3 {baseDir}/scripts/hik_open_video_recording.py project-create \
  --project-name "项目名称" \
  --expire-days 3 \
  --flow-limit 10240000

Session Persistence

Medium
Category
Rogue Agent
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.

Content

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

创建项目:

bash
python3 {baseDir}/scripts/hik_open_video_recording.py project-create \
  --project-name "项目名称" \
  --expire-days 3 \
  --flow-limit 10240000

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill supports file upload/download and JSON output containing request context and raw responses, but it provides no guidance on handling sensitive media, metadata, or tokens that may appear in responses or logs. This raises the risk of privacy leakage, overexposure of video content, or accidental disclosure of internal identifiers and authentication-related data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill exposes destructive operations such as project deletion, file deletion, and task termination without documenting any confirmation step, safety prompt, or operator warning. In an autonomous or semi-autonomous agent workflow, this increases the chance of accidental destructive actions against production video assets and recording jobs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file states that the skill will automatically obtain, cache, refresh, and inject OAuth access tokens, and it lists sensitive environment variables including a client secret. The description does not include any warning that the skill will use stored credentials and make authentication requests to an external service, which is a user-relevant privacy and safety disclosure for markdown files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents operations such as project-delete, task-stop, and file-delete, but it does not include any cautionary language about data loss, interruption of active work, or irreversibility. For markdown files, safety-affecting behaviors should be disclosed so users understand the risk before invoking the skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script caches OAuth access tokens on disk under the user's home directory without setting restrictive file permissions or warning the user that bearer credentials will be persisted. On multi-user systems or misconfigured environments, another local process or user could read the token and reuse it to access the Hik-Cloud APIs until expiration.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The script sends client_id and client_secret to obtain an OAuth token, and many other commands transmit device identifiers, project IDs, validate codes, and recording parameters to a remote API. There is no user-visible warning, logging, or descriptive help text in this file explaining that sensitive operational data is sent over the network.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script defines a project deletion request and later a file deletion request, both of which can remove remote resources, but there is no confirmation prompt, warning text, or explanatory documentation in this file. Because these are irreversible remote delete actions, users are not clearly informed before invoking them.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This request issues an HTTP DELETE for a remote file identified by projectId and fileId. The file contains no user-facing disclosure, confirmation step, or inline warning that invoking the corresponding command deletes stored video data.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/hik_open_video_recording.py (reported line 97)May include surrounding context.

python
return

    for method_name in ("SetConsoleOutputCP", "SetConsoleCP"):
        method = getattr(kernel32, method_name, None)
        if not callable(method):
            continue
        try:

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

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