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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
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.

Content

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

md
[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

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

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

Clear Cache:

bash
rm -rf /tmp/ezviz_global_token_cache/

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

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

Clear Cache:

bash
rm -rf /tmp/ezviz_global_token_cache/

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

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

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

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

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

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

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

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

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

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

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 · SKILL.md (reported line 296)May include surrounding context.

md
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

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 · lib/token_manager.py (reported line 120)May include surrounding context.

python
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

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 · lib/token_manager.py (reported line 189)May include surrounding context.

python
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

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

python
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

Credential Access

High
Category
Privilege Escalation
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.

Content

Scanner excerpt · lib/token_manager.py (reported line 173)May include surrounding context.

python
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

Credential Access

High
Category
Privilege Escalation
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.

Content

Scanner excerpt · lib/token_manager.py (reported line 361)May include surrounding context.

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

Missing User Warnings

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

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

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

text

---

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

md
## 🔒 Security Recommendations

### 1. Use Minimal Permission Credentials
- Create dedicated appKey/appSecret
- Do not use master account credentials
- Rotate credentials regularly (recommended every 90 days)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

Use .env file

echo "EZVIZ_APP_KEY=your_key" >> .env echo "EZVIZ_APP_SECRET=your_secret" >> .env chmod 600 .env source .env

text

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.