Back to skill

Security audit

Ezviz Open Safety Production Inspection

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent, but it handles camera images, credentials, token persistence, and remote agent creation in ways that deserve review before use.

Review this carefully before installing. Use a dedicated least-privilege Ezviz app, test with non-production cameras, disable token caching with EZVIZ_TOKEN_CACHE=0 in shared environments, avoid passing secrets on the command line, and be aware that running the skill may create or rename a persistent Ezviz intelligent agent and send camera image URLs to Ezviz AI analysis.

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
lib/token_manager.py:45
Finding

Predictable Shared Temporary Cache Path Can Expose Access Tokens

Content
View full analysis

Vulnerability Details

File Location: lib/token_manager.py, lines 45-51 and 97-110
Vulnerability Type: Unsafe temporary file and directory handling
Risk Level: High

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)
        
        return True

Technical Analysis

The token cache is placed in the predictable shared path /tmp/ezviz_global_token_cache/. The implementation creates this directory with exist_ok=True but does not verify that it is a real directory, that it is owned by the current user, or that it has restrictive permissions.

The temporary filename, global_token_cache.json.tmp, is also predictable. Opening it with the ordinary open(..., 'w') interface follows a pre-existing symbolic link. The intended 0600 permissions are applied only after the temporary file has been written and renamed. Consequently:

  • An attacker may pre-create the cache directory with insecure permissions.
  • An attacker may pre-create the predictable temporary path as a symbolic link.
  • The temporary file may initially inherit a permissive process umask.
  • Sen ...[truncated 1905 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer a per-user runtime directory such as $XDG_RUNTIME_DIR instead of a globally predictable path under /tmp.
  2. Create the cache directory with mode 0700 and verify that:
    • It is a directory rather than a symbolic link.
    • It is owned by the effective user.
    • It is not writable by group or other users.
  3. Create temporary files using tempfile.mkstemp(dir=cache_dir) or tempfile.NamedTemporaryFile(dir=cache_dir, delete=False).
  4. Set mode 0600 at creation time, before writing token data.
  5. Where supported, use os.open() with O_CREAT, O_EXCL, and O_NOFOLLOW to prevent link-following and filename-reuse attacks.
  6. Validate the final cache file with os.lstat() before reading it, rejecting symbolic links, unexpected owners, and unsafe permission modes.
  7. Flush and fsync() the temporary file before atomic replacement when cache durability is required.
  8. Disable token caching by default in multi-user environments or use an operating-system credential store.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/safety_production_inspection.py:439
Finding

Application Secret Can Be Exposed Through Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/safety_production_inspection.py, lines 439-446
Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: Medium

Vulnerable Code:

python
if len(sys.argv) >= 4:
    app_key = sys.argv[1]
    app_secret = sys.argv[2]
    device_serial = sys.argv[3]
    if len(sys.argv) >= 5:
        channel_no = sys.argv[4]
    if len(sys.argv) >= 6:
        template_id = sys.argv[5]

The supported interface is also presented to users as:

text
python3 safety_production_inspection.py app_key app_secret device_serial [channel_no] [template_id]

Technical Analysis

The script accepts the long-lived Ezviz application secret as a positional command-line argument. Process arguments are not an appropriate secret-transport mechanism because they may be exposed through:

  • Process inspection utilities and operating-system process metadata.
  • Shell command history.
  • Job schedulers and orchestration metadata.
  • Monitoring, endpoint security, and audit telemetry.
  • Debug logs or wrapper scripts that record complete commands.

Environment variables and configuration files are checked by the script, but retaining and documenting the positional-secret interface allows users or automation to select the unsafe path. The credential is sent only to the declared Ezviz token endpoint once loaded; the issue is its local exposure before or during execution.

Attack Path

  1. An operator follows the supported syntax and supplies the application secret as sys.argv[2].
  2. The shell records the command in history, or the operating system exposes the command line while the process is running.
  3. A local user, monitoring service, log collector, or other process with applicable visibility retrieves the argument string.
  4. The observer extracts the Ezviz application key and secret.
  5. The observer submits those credentials to th ...[truncated 1044 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove support for supplying app_secret as a positional command-line argument.
  2. For interactive operation, obtain the secret with getpass.getpass() so it is neither echoed nor included in process arguments.
  3. For automated operation, integrate with an operating-system credential store or deployment-platform secret manager.
  4. If environment-variable support is retained, document that process environments can also be exposed under some operating-system and monitoring configurations.
  5. Require strict owner-only permissions for configuration files containing credentials and reject files with unsafe ownership or modes.
  6. Update all usage messages and documentation so they never recommend embedding credentials in a command.
  7. Use dedicated, least-privilege Ezviz credentials and rotate any secret previously supplied through command-line arguments.
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill claims a narrow inspection workflow, but the detected behavior expands into reading credentials from local config, managing shared token cache files, and querying/creating/renaming remote Ezviz agents. This is a broader remote-management and local-secret-handling capability than the headline description suggests, so a user may approve the skill without understanding that it can alter persistent remote resources and touch local configuration.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims a narrow inspection workflow, but the detected behavior expands into reading credentials from local config, managing shared token cache files, and querying/creating/renaming remote Ezviz agents. This is a broader remote-management and local-secret-handling capability than the headline description suggests, so a user may approve the skill without understanding that it can alter persistent remote resources and touch local configuration.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
for f in ['SKILL.md', 'scripts/safety_production_inspection.py', 'lib/token_manager.py']:

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 121)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 174)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 190)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/safety_production_inspection.py (reported line 130)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/safety_production_inspection.py (reported line 132)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/safety_production_inspection.py (reported line 520)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/safety_production_inspection.py (reported line 523)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
95% confidence
Finding

The CLI prints the access token value, even if truncated, which can leak sensitive bearer credentials into terminal history, logs, CI output, support captures, or shell recordings. Because bearer tokens can often be used directly for API access, exposing any substantial token prefix materially increases the chance of credential compromise in operational environments.

Content

Scanner excerpt · lib/token_manager.py (reported line 362)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:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents substantial capabilities and side effects—environment access, local file reads/writes, network calls, and shell-based verification commands—but does not declare a formal tool scope such as permissions or allowed-tools. This weakens the trust boundary for users and platforms, because the effective behavior is broader than what a permission model would explicitly authorize, increasing the chance of silent overreach.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
89% confidence
Finding

The skill explicitly persists authentication state in a shared token cache under /tmp, which creates session persistence beyond a single run. Even with 0600 permissions, persistent tokens on disk increase the blast radius of host compromise, accidental reuse across contexts, and unauthorized access if multiple processes or users interact with the same environment.

Content

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

md
warnings:
      - "Use dedicated Ezviz credentials (not main account)"
      - "Queries intelligent agent list"
      - "May create agent from template"
      - "Captures device images"
      - "Sends images to aidialoggw.ys7.com"
      - "Token cached in /tmp/ezviz_global_token_cache/ (600)"

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README states that the agent name must contain '安全生产' as a compliance requirement. This is a natural-language locale/language constraint, and the file does not offer a user choice, opt-in, or region-specific justification sufficient to show that all users must operate in Chinese.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code persists live access tokens in a shared system temporary directory, which increases the risk of local credential disclosure through other processes, users, backups, or weak temp-directory hygiene. Although the file is chmodded to 0600 after writing, the parent directory is global and the temp file is created before permissions are tightened, so the design still stores sensitive secrets in a broadly shared filesystem location.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill silently reads Ezviz credentials, device identifiers, and template IDs from multiple local OpenClaw config files when explicit inputs are missing. That exceeds the minimum scope implied by a simple inspection script and can cause the skill to access unrelated accounts or devices without clear user intent, especially in shared environments.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/safety_production_inspection.py (reported line 177)May include surrounding context.

python
agents = []
        # Handle both response formats
        if 'data' in result:
            if isinstance(result['data'], dict) and 'appList' in result['data']:
                agents = result['data']['appList']
            elif isinstance(result['data'], list):
                agents = result['data']

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/safety_production_inspection.py (reported line 178)May include surrounding context.

python
agents = []
        # Handle both response formats
        if 'data' in result:
            if isinstance(result['data'], dict) and 'appList' in result['data']:
                agents = result['data']['appList']
            elif isinstance(result['data'], list):
                agents = result['data']

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code comments and behavior require selecting or creating agents whose names contain '安全生产', and elsewhere uses fixed Chinese naming/content conventions. This is a natural-language locale constraint embedded in the skill, but the file does not provide any user opt-in or explain why Chinese-only naming is mandatory for all users.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
76% confidence
Finding

If no matching agent exists, the skill automatically creates a new remote intelligent agent from a template, persisting resources and state in the user's Ezviz account. This is a durable remote side effect that can lead to account clutter, unintended billing or governance issues, and changes to production environments without an explicit confirmation checkpoint.

Content

Scanner excerpt · scripts/safety_production_inspection.py (reported line 196)May include surrounding context.

python
print(f"[SUCCESS] Using existing agent: {agent_id}")
                    return agent_id
            
            # No agent with '安全生产' found - will create new one
            print("[INFO] No agent with '安全生产' found - will create new one from template")
            return None
        else:

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

python
}
    
    try:
        response = requests.post(update_url, headers=headers, json=data, timeout=30)
        result = response.json()
        
        if result.get('code') == '200' or (result.get('meta', {}).get('code') == 200):

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The skill sends captured device image URLs and analysis prompts to a separate AI analysis endpoint, which exposes potentially sensitive workplace imagery to an external service. Even though this is the skill's core function and is disclosed in output text, the implementation treats printed notice as implied consent and does not enforce explicit user authorization or data minimization.

Content

Scanner excerpt · scripts/safety_production_inspection.py (reported line 364)May include surrounding context.

python
}
    
    try:
        response = requests.post(ANALYSIS_URL, headers=headers, json=payload, timeout=60)
        result = response.json()
        
        if result.get('meta', {}).get('code') == 200:

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation elsewhere explicitly states the skill uses both open.ys7.com and aidialoggw.ys7.com for capture and AI analysis, but the pre-run verification step says the code "should use open.ys7.com only." That is an active contradiction in the file's own guidance and can mislead reviewers about the actual remote destinations involved.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The natural-language documentation prominently uses Chinese for the feature description while other parts are in English, without indicating language options or intended locale scope. Under the stated policy, forcing or assuming a language without opt-in can be a locale-policy issue unless the constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.