Back to skill

Security audit

Ezviz Open Camera Video

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned but needs review because it exposes reusable camera access tokens through ordinary output, examples, and a shared temp cache.

Review before installing. Remove the hardcoded example credentials, revoke or rotate them if they were ever real, remove or gate the debug token_result printing, and treat generated preview URLs as secrets because they contain bearer tokens. Prefer environment variables over command-line secrets or config-file fallback, and disable token caching or run in an isolated user/container if camera privacy matters.

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

T09 · Insecure Skill Coding Practices

Error
Location
lib/README_TOKEN_MANAGER.md:114
Finding
Hardcoded Ezviz Application Credentials in Documentation## Vulnerability Details **File Location**: `lib/README_TOKEN_MANAGER.md`, lines 114–118 **Vulnerability Type**: Hardcoded credentials **Risk Level**: High ### Vulnerable Code ```bash # 2. First retrieval from the API python3 lib/token_manager.py get --app-key "26810f3acd794862b608b6cfbc32a6b8" --app-secret "3155063e93f09f377eaf5ba9f321f8c2" # Output: From Cache: False # 3. Retrieve again from the cache python3 lib/token_manager.py get --app-key "26810f3acd794862b608b6cfbc32a6b8" --app-secret "3155063e93f09f377eaf5ba9f321f8c2" ``` ### Technical Analysis The documentation contains a concrete Ezviz application key and application secret instead of unmistakable placeholder values. Anyone able to read the repository, a distributed Skill package, a mirror, or its version history can recover these credentials. Static analysis cannot determine whether the credentials are still active or what permissions they possess. Nevertheless, application secrets committed to a repository must be considered compromised. The secret can be submitted to the public Ezviz token endpoint together with the corresponding application key to request a bearer access token. ### Attack Path 1. An attacker obtains the Skill package or accesses a repository copy or historical commit. 2. The attacker extracts the hardcoded application key and secret from `lib/README_TOKEN_MANAGER.md`. 3. The attacker sends the credentials to `https://openai.ys7.com/api/lapp/token/get`. 4. If the credentials remain valid, Ezviz returns an access token. 5. The attacker uses that token with Ezviz APIs or preview facilities permitted by the application. ### Impact Assessment Successful exploitation can grant access to the Ezviz resources and operations authorized for the exposed application. Depending on the server-side permissions assigned to it, this could include viewing camera streams, playback access, device information, or other Ezviz API operations. The avai ...[truncated 106 chars]
Remediation
## Remediation Suggestions 1. Revoke and rotate the exposed application secret immediately. 2. Review Ezviz access and API logs for unauthorized use of the exposed credentials. 3. Replace all concrete credentials with obvious placeholders such as `YOUR_EZVIZ_APP_KEY` and `YOUR_EZVIZ_APP_SECRET`. 4. Remove the credentials from repository history, archived packages, mirrors, build artifacts, and documentation caches where feasible. 5. Add automated secret scanning to pre-commit hooks and CI pipelines. 6. Use a dedicated Ezviz application with only the permissions required to produce preview links.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_preview.py:282
Finding
Full Bearer Access Token Disclosed Through Unconditional Debug Logging## Vulnerability Details **File Location**: `scripts/generate_preview.py`, lines 282–292 **Vulnerability Type**: Sensitive token exposure through logs **Risk Level**: High ### Vulnerable Code ```python try: token_result = get_cached_token(app_key, app_secret, use_cache=use_cache) print(f"[DEBUG] token_result keys: {token_result.keys()}") print(f"[DEBUG] token_result: {token_result}") # Compatible with different return formats access_token = token_result.get('accessToken') or token_result.get('access_token') expire_time = token_result.get('expireTime') or token_result.get('expire_time', 'Unknown') if not access_token: print(f"[ERROR] No access_token in result: {token_result}") ``` ### Technical Analysis A successful `get_cached_token` call returns a dictionary containing the complete `access_token`. The code unconditionally prints that dictionary to standard output. The error branch can also print the complete result object. This disclosure occurs during ordinary execution and is not restricted by a debug-mode setting. It also bypasses the script's later `mask_token` function. Standard output may be retained in terminal history, Agent conversations, job logs, monitoring systems, support bundles, or subprocess output collected by another application. Access tokens are bearer credentials: possession of a token may be sufficient to perform operations within its server-side authorization scope until it expires or is revoked. ### Attack Path 1. A legitimate user or automated Agent executes the preview script. 2. The script obtains a fresh or cached access token. 3. The complete token is printed as part of `token_result`. 4. An attacker with access to terminal output, Agent transcripts, CI logs, process output, or log aggregation extracts the token. 5. The attacker reuses the bearer token with Ezviz preview links or supported API calls before expiration. ### Impact Assess ...[truncated 380 chars]
Remediation
## Remediation Suggestions 1. Remove the unconditional printing of `token_result`. 2. Do not include the result object in error messages because it may contain sensitive values. 3. Log only an allowlist of non-sensitive fields, such as `success`, `expire_time`, and `from_cache`. 4. If diagnostic logging is required, make it explicitly opt-in and apply centralized redaction to fields named `access_token`, `accessToken`, `app_secret`, and `appSecret`. 5. Treat existing execution logs as potentially compromised and remove them from retained systems where practical. 6. Revoke tokens that may already have appeared in shared logs or transcripts.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_preview.py:64
Finding
Bearer Tokens Embedded in and Printed as URL Query Parameters## Vulnerability Details **File Location**: `scripts/generate_preview.py`, lines 64–89 **Vulnerability Type**: Sensitive credential exposure through URLs and output **Risk Level**: Medium ### Vulnerable Code ```python def generate_links(access_token, device_serial, channel_no): """Generate preview links (live + playback)""" # Live links live_pc_url = ( f"https://openai.ys7.com/console/jssdk/pc.html" f"?url=ezopen://open.ys7.com/{device_serial}/{channel_no}.live" f"&accessToken={access_token}" ) live_mobile_url = ( f"https://openai.ys7.com/console/jssdk/mobile.html" f"?url=ezopen://open.ys7.com/{device_serial}/{channel_no}.live" f"&accessToken={access_token}" ) # Playback links playback_pc_url = ( f"https://openai.ys7.com/console/jssdk/pc.html" f"?url=ezopen://open.ys7.com/{device_serial}/{channel_no}.rec" f"&accessToken={access_token}" ) playback_mobile_url = ( f"https://openai.ys7.com/console/jssdk/mobile.html" f"?url=ezopen://open.ys7.com/{device_serial}/{channel_no}.rec" f"&accessToken={access_token}" ) return live_pc_url, live_mobile_url, playback_pc_url, playback_mobile_url ``` The generated values are then emitted in full: ```python print(f" {live_pc_url}") print(f" {live_mobile_url}") print(f" {playback_pc_url}") print(f" {playback_mobile_url}") result = { 'device': device_serial, 'channel': channel_no, 'live': { 'pc_url': live_pc_url, 'mobile_url': live_mobile_url }, 'playback': { 'pc_url': playback_pc_url, 'mobile_url': playback_mobile_url }, 'token_masked': mask_token(access_token), 'generated_at': datetime.now().isoformat() } print(json.dumps(result, indent=2, ensure_ascii=False)) ``` ### Technical Analysis T ...[truncated 1752 chars]
Remediation
## Remediation Suggestions 1. Do not print complete token-bearing URLs by default. 2. Return redacted links in normal logs and require an explicit option, such as `--show-sensitive-links`, before exposing complete URLs. 3. For automation, write sensitive output to a caller-selected file created with owner-only permissions instead of standard output. 4. Avoid duplicating complete URLs in both human-readable and JSON output. 5. Add clear warnings that generated URLs are bearer credentials and must not be shared or logged. 6. Use narrowly scoped and short-lived preview credentials if the Ezviz platform supports them. 7. Ensure masking always redacts tokens regardless of their length. 8. Configure downstream systems to redact `accessToken` query parameters.

T09 · Insecure Skill Coding Practices

Warning
Location
lib/token_manager.py:44
Finding
Predictable Shared Temporary Token Cache Uses Unsafe File-Creation Semantics## Vulnerability Details **File Location**: `lib/token_manager.py`, lines 44–47 and 96–109 **Vulnerability Type**: Unsafe temporary file and shared secret storage **Risk Level**: Medium ### Vulnerable Code ```python def get_cache_dir(): """Get global cache directory path.""" base_temp = tempfile.gettempdir() cache_dir = os.path.join(base_temp, CACHE_DIR_NAME) os.makedirs(cache_dir, exist_ok=True) return cache_dir ``` ```python def save_token_cache(cache_data): """ Save all tokens to global cache file (atomic write). Args: cache_data: Dict of all cached tokens """ cache_file = get_cache_file_path() cache_dir = get_cache_dir() try: # Write to temp file first, then rename (atomic operation) temp_file = cache_file + ".tmp" with open(temp_file, 'w') as f: json.dump(cache_data, f, indent=2) os.replace(temp_file, cache_file) # Set file permissions (readable only by owner) os.chmod(cache_file, 0o600) ``` ### Technical Analysis The cache is stored under a globally predictable directory and filename in the system temporary directory. The implementation does not explicitly create or verify the cache directory as owner-only, does not verify path ownership, and does not reject symbolic links or unexpected existing files. The temporary filename is also fixed and predictable. It is opened using regular `open(..., 'w')`, which follows symbolic links. Restrictive permissions are applied only to the final cache file after writing and replacement. Consequently, final mode `0600` does not fully address path-substitution, pre-creation, or pre-write risks. Atomic replacement protects readers from partially written JSON but does not make use of a predictable shared path safe against an untrusted local process. The design also stores tokens for multiple credential identities in one shared file, ...[truncated 1354 chars]
Remediation
## Remediation Suggestions 1. Store tokens in a per-user private state or cache directory rather than a globally named shared temporary directory. 2. Create the cache directory with mode `0700` and verify that it is owned by the current user and is not a symbolic link. 3. Create temporary files with `tempfile.mkstemp` or `NamedTemporaryFile` inside the verified private directory. 4. Apply mode `0600` at file creation time rather than only after sensitive data has been written. 5. Use no-follow and exclusive-creation protections where supported, and reject unexpected file types or ownership. 6. Keep atomic replacement, but validate the source and destination paths before replacement. 7. Prefer separate cache files for distinct credential identities to reduce compromise scope. 8. Disable caching by default in shared or multi-tenant environments and document the residual local-security assumptions.
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (31)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is presented as using environment variables to generate links, but the documentation reveals additional sensitive behaviors: reading credentials from local config files, accepting secrets via command-line arguments, and printing full URLs that embed access tokens. Those behaviors can expose secrets through shell history, process listings, logs, or accidental disclosure, and they are not adequately reflected in the high-level description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is presented as using environment variables to generate links, but the documentation reveals additional sensitive behaviors: reading credentials from local config files, accepting secrets via command-line arguments, and printing full URLs that embed access tokens. Those behaviors can expose secrets through shell history, process listings, logs, or accidental disclosure, and they are not adequately reflected in the high-level description.

Credential Access

High
Category
Privilege Escalation
Content
[OK] Using credentials from environment variables

======================================================================
[Step 1] Getting access token...
======================================================================
[INFO] Using cached global token, expires: 2026-03-26 19:21:16
[SUCCESS] Using cached token, expires: 2026-03-26 19:21:16
Confidence
97% confidence
Finding
The documented output includes full preview URLs containing the access token in the query string. Printing bearer tokens to terminal output can leak them into logs, transcripts, screenshots, scrollback buffers, and monitoring tools, allowing unauthorized reuse during token validity.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Clear Cache**:
```bash
rm -rf /tmp/ezviz_global_token_cache/
```

---
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Clear Cache**:
```bash
rm -rf /tmp/ezviz_global_token_cache/
```

---
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
### 2. Environment Variable Security
```bash
# Use .env file
echo "EZVIZ_APP_KEY=your_key" >> .env
echo "EZVIZ_APP_SECRET=your_secret" >> .env
chmod 600 .env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Environment Variable Security
```bash
# Use .env file
echo "EZVIZ_APP_KEY=your_key" >> .env
echo "EZVIZ_APP_SECRET=your_secret" >> .env
chmod 600 .env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Environment Variable Security
```bash
# Use .env file
echo "EZVIZ_APP_KEY=your_key" >> .env
echo "EZVIZ_APP_SECRET=your_secret" >> .env
chmod 600 .env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Environment Variable Security
```bash
# Use .env file
echo "EZVIZ_APP_KEY=your_key" >> .env
echo "EZVIZ_APP_SECRET=your_secret" >> .env
chmod 600 .env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Environment Variable Security
```bash
# Use .env file
echo "EZVIZ_APP_KEY=your_key" >> .env
echo "EZVIZ_APP_SECRET=your_secret" >> .env
chmod 600 .env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def get_cached_token(app_key, app_secret, use_cache=None):
    """
    Get access token, using cached version if available and valid.
    
    Args:
        app_key: Ezviz app key
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def get_cached_token(app_key, app_secret, use_cache=None):
    """
    Get access token, using cached version if available and valid.
    
    Args:
        app_key: Ezviz app key
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def get_cached_token(app_key, app_secret, use_cache=None):
    """
    Get access token, using cached version if available and valid.
    
    Args:
        app_key: Ezviz app key
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def get_cached_token(app_key, app_secret, use_cache=None):
    """
    Get access token, using cached version if available and valid.
    
    Args:
        app_key: Ezviz app key
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def refresh_token(app_key, app_secret, cache_key=None):
    """
    Get new access token from Ezviz API and save to cache.
    
    Args:
        app_key: Ezviz app key
Confidence
91% confidence
Finding
This function obtains a fresh EZVIZ access token and then persists the full bearer token to a shared cache file in the system temporary directory. Even with mode 0600 on the file, using a global temp-based shared cache can expose tokens to other processes running as the same user, and the cached token becomes a reusable secret if the host or account is compromised.

Credential Access

High
Category
Privilege Escalation
Content
result = get_cached_token(args.app_key, args.app_secret, use_cache=use_cache)
        
        if result["success"]:
            print(f"\nAccess Token: {result['access_token'][:30]}...")
            print(f"Expires: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(result['expire_time'] / 1000))}")
            print(f"From Cache: {result['from_cache']}")
        else:
Confidence
98% confidence
Finding
The CLI prints the first 30 characters of the access token to stdout, which is sensitive bearer credential material. Partial token disclosure can leak enough data into shell history, CI logs, terminal recordings, or observability systems to aid token theft or correlation, and in some environments any token fragment should be treated as secret.

Missing User Warnings

High
Confidence
99% confidence
Finding
The debug output prints the full token response, which likely contains the access token and related metadata. That exposes bearer credentials to logs and consoles, enabling unauthorized stream access or token reuse by anyone who can read process output or aggregated logs.

Missing User Warnings

High
Confidence
99% confidence
Finding
The script prints complete live and playback URLs containing the access token to stdout and JSON output. Since query-string bearer tokens are immediately usable, this turns normal output channels into a credential disclosure path and could expose private surveillance feeds through shell history, CI logs, transcripts, or monitoring systems.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill documentation describes capabilities such as reading environment variables, reading local config files, writing a token cache, invoking Python via shell, and making outbound network requests, but it does not declare an explicit tool scope like permissions or allowed-tools. That omission weakens policy enforcement and user awareness, making it easier for a skill with credential and filesystem access to operate with broader privileges than expected.

Session Persistence

Medium
Category
Rogue Agent
Content
export EZVIZ_TOKEN_CACHE=0

# 3. Test credentials (recommended to use test account first)
# Login to https://openai.ys7.com/ to create dedicated app with only preview permissions
```

---
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
## 🔒 Security Recommendations

### 1. Use Minimal Permission Credentials
- Create dedicated appKey/appSecret
- Do not use master account credentials
- Rotate credentials regularly (recommended every 90 days)
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# Use .env file
echo "EZVIZ_APP_KEY=your_key" >> .env
echo "EZVIZ_APP_SECRET=your_secret" >> .env
chmod 600 .env
source .env
```
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The file states that it provides unified global token cache management for all EZVIZ skills and that all skills share the same token cache. A video streaming skill may reasonably obtain credentials, but operating a shared auth cache for multiple skills is a separate platform-level capability not justified by the manifest's narrow streaming/link-generation purpose.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The manifest describes a skill for generating EZVIZ live/playback viewing links, but this file documents command-line operations to get, refresh, list, and clear global tokens. Managing shared authentication state across skills is a broader infrastructure capability than remote viewing/link generation and is not justified by the stated skill purpose.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The README explicitly instructs users to pass app-secret values on the command line in plaintext. Command-line arguments are commonly exposed through shell history, process listings, audit logs, and terminal recordings, so this guidance can directly lead to credential disclosure and subsequent unauthorized API access.

Static analysis

No suspicious patterns detected.