Back to skill

Security audit

Aliyun Oss

Security checks for vulnerabilities and agentic risk

Overview

The skill is an Aliyun OSS uploader with a coherent purpose, but it can upload arbitrary readable local files to cloud storage without strong scoping or user confirmation.

Review before installing. Use this only with a tightly scoped Aliyun RAM user or STS credentials, restrict the agent to upload only explicit user-selected media or workspace files, avoid enabling public-read ACLs, and protect /root/.openclaw/aliyun-oss-config.json with strict permissions and rotation.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
aliyun_oss_uploader.py:84
Finding
Unrestricted Local File Upload Allows Sensitive Host Data Exposure<![CDATA[ ## Vulnerability Details **File Location**: `main.py:29-33`, `handle_media.py:14-29`, `aliyun_oss_uploader.py:84-133`, `security_validator.py:79-109` **Vulnerability Type**: Missing path authorization and disconnected security validation **Risk Level**: High ### Vulnerable Code ```python # main.py:29-33 from aliyun_oss_uploader import AliyunOSSUploader uploader = AliyunOSSUploader() file_path = sys.argv[2] prefix = sys.argv[3] if len(sys.argv) > 3 else "" result = uploader.upload_single_file(file_path, oss_key=prefix if prefix else None) ``` ```python # handle_media.py:14-29 def handle_media(file_path: str) -> str: """ OpenClaw standard media processing interface. """ try: from aliyun_oss_uploader import AliyunOSSUploader uploader = AliyunOSSUploader() # Upload file result = uploader.upload_single_file(file_path) ``` ```python # aliyun_oss_uploader.py:84-133 def upload_single_file( self, local_file: str, oss_key: Optional[str] = None, rename_strategy: str = "uuid", public_read: bool = False ) -> Dict[str, str]: # Validate that the file exists if not os.path.exists(local_file): raise FileNotFoundError(f"File does not exist: {local_file}") # Validate file size if not self.validate_file_size(local_file): raise ValueError(f"File exceeds size limit: {local_file}") # Generate OSS key if oss_key is None: filename = os.path.basename(local_file) unique_filename = self.generate_unique_filename(filename, rename_strategy) oss_key = unique_filename elif '/' not in oss_key and not oss_key.startswith('/'): prefix = self.config.get('default_prefix', '') if prefix: oss_key = f"{prefix.rstrip('/')}/{oss_key}" file_size = os.path.getsize(local_file) large_file_threshold = self.config.get( 'large_file_threshold_mb', 100 ) * 1024 * 1024 try: if file_size > large_file_thre ...[truncated 3085 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Enforce authorization in the upload sink** - Integrate validation directly into `upload_single_file()` so no CLI, media handler, or future caller can bypass it. - Do not rely exclusively on checks in entry-point code. 2. **Restrict uploads to approved roots** - Define explicit media or workspace directories in configuration. - Resolve the requested path with `Path.resolve(strict=True)`. - Verify that the canonical path is a descendant of an approved root using `Path.is_relative_to()` or an equivalent safe comparison. 3. **Require regular files** - Reject symbolic links and non-regular filesystem objects. - Use `os.lstat()` and `stat.S_ISREG()` to reject devices, sockets, FIFOs, and directories. - Where practical, open files with protections such as `O_NOFOLLOW` and validate the opened descriptor to reduce time-of-check/time-of-use races. 4. **Apply file policy controls** - Enforce configured extension rules. - Validate content using trusted MIME detection or file signatures rather than extensions alone. - Retain size limits and introduce conservative defaults for Agent-triggered uploads. 5. **Protect sensitive paths** - Explicitly deny the OpenClaw configuration directory, credential stores, SSH directories, environment files, and other secret-bearing locations. - Treat deny lists only as defense in depth; an approved-root policy should remain the primary control. 6. **Add user authorization** - Require explicit confirmation before uploading paths not supplied as genuine media attachments. - Display the canonical local path, destination bucket, object key, and intended ACL before upload. 7. **Reduce process privileges** - Run the Skill under a dedicated non-root account with access only to the required media directory. - Mount secret directories and unrelated user data as inaccessible to the uploader process. 8. **Add regression tests** - Confirm rejection of `../ ...[truncated 125 chars]

T09 · Insecure Skill Coding Practices

Warning
Location
aliyun_oss_uploader.py:38
Finding
Long-Lived Aliyun Access Keys Are Used Without Enforcing Credential Safeguards<![CDATA[ ## Vulnerability Details **File Location**: `aliyun_oss_uploader.py:38-55`, `sts_manager.py:12-35`, `security_validator.py:59-75` **Vulnerability Type**: Insecure credential management and unused permission validation **Risk Level**: Medium ### Vulnerable Code ```python # aliyun_oss_uploader.py:38-55 with open(self.config_path, 'r', encoding='utf-8') as f: return json.load(f) def init_oss_client(self): auth_config = self.config.get('auth', {}) if 'access_key_id' not in auth_config or 'access_key_secret' not in auth_config: raise ValueError( "Configuration is missing access_key_id and access_key_secret" ) self.auth = oss2.Auth( auth_config['access_key_id'], auth_config['access_key_secret'] ) endpoint = self.config['endpoint'] bucket_name = self.config['bucket_name'] self.bucket = oss2.Bucket(self.auth, endpoint, bucket_name) ``` ```python # sts_manager.py:22-35 with open(self.config_path, 'r', encoding='utf-8') as f: return json.load(f) def get_credentials(self) -> Dict[str, str]: auth_config = self.config.get('auth', {}) if 'access_key_id' not in auth_config or 'access_key_secret' not in auth_config: raise ValueError( "Configuration is missing access_key_id or access_key_secret" ) return { 'access_key_id': auth_config['access_key_id'], 'access_key_secret': auth_config['access_key_secret'] } ``` ```python # security_validator.py:59-75 def validate_oss_permissions(self, oss_config: Dict[str, Any]) -> bool: # Check whether STS temporary credentials are in use if 'security_token' not in oss_config: self.logger.warning( "STS temporary credentials were not detected; this may be unsafe" ) return False required_permissions = ['PutObject', 'GetObject'] # RAM role policy validation could be added here return True ``` The English text in the comments and exc ...[truncated 2811 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Use short-lived STS credentials** - Implement Aliyun STS role assumption. - Initialize OSS access with `oss2.StsAuth(access_key_id, access_key_secret, security_token)`. - Refresh credentials before expiration and avoid persisting temporary credentials longer than necessary. 2. **Remove raw credential-returning APIs** - Replace `AuthManager.get_credentials()` with an API that constructs and returns an authenticated client. - Avoid exposing raw secrets to unrelated callers. 3. **Enforce least privilege** - Scope RAM policy to the required bucket and approved object prefix. - Permit only required actions, such as `PutObject`, narrowly scoped `GetObject`, multipart operations, and only required listing operations. - Do not grant deletion, ACL modification, or broad account-level OSS permissions unless operationally necessary. 4. **Validate credential-file security** - Require the file to be owned by the expected service account. - Reject group-readable or world-readable modes; enforce an equivalent of mode `0600`. - Resolve and validate the configuration path and reject unexpected symbolic links. - Fail securely when ownership or permissions are unsafe. 5. **Use a managed secret store** - Prefer an operating-system credential facility, container secret, or cloud secret-management service over a general JSON configuration file. - Keep non-secret OSS settings separate from credentials. 6. **Make security checks operational** - Invoke credential and permission validation during uploader initialization. - Fail closed when temporary credentials are required but absent. - Replace the placeholder permission check with deployment-time policy validation or documented automated infrastructure checks. 7. **Rotate and monitor** - Rotate any existing long-lived credentials after migration. - Enable OSS access logging and alerts for anomalous listing, downloads, ACL changes, or u ...[truncated 31 chars]
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The most serious mismatch is that the skill reportedly reads /root/.openclaw/aliyun-oss-config.json and retrieves access_key_id/access_key_secret despite not implementing the promised OSS upload or temporary-link features. Accessing cloud credentials without clear necessity or user-visible justification creates direct secret-exposure risk and can enable unauthorized access to the user's OSS bucket.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The most serious mismatch is that the skill reportedly reads /root/.openclaw/aliyun-oss-config.json and retrieves access_key_id/access_key_secret despite not implementing the promised OSS upload or temporary-link features. Accessing cloud credentials without clear necessity or user-visible justification creates direct secret-exposure risk and can enable unauthorized access to the user's OSS bucket.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The most serious mismatch is that the skill reportedly reads /root/.openclaw/aliyun-oss-config.json and retrieves access_key_id/access_key_secret despite not implementing the promised OSS upload or temporary-link features. Accessing cloud credentials without clear necessity or user-visible justification creates direct secret-exposure risk and can enable unauthorized access to the user's OSS bucket.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The most serious mismatch is that the skill reportedly reads /root/.openclaw/aliyun-oss-config.json and retrieves access_key_id/access_key_secret despite not implementing the promised OSS upload or temporary-link features. Accessing cloud credentials without clear necessity or user-visible justification creates direct secret-exposure risk and can enable unauthorized access to the user's OSS bucket.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The most serious mismatch is that the skill reportedly reads /root/.openclaw/aliyun-oss-config.json and retrieves access_key_id/access_key_secret despite not implementing the promised OSS upload or temporary-link features. Accessing cloud credentials without clear necessity or user-visible justification creates direct secret-exposure risk and can enable unauthorized access to the user's OSS bucket.

Credential Access

High
Category
Privilege Escalation
Content
validator = SecurityValidator(config)
    
    # 测试文件(需要实际文件路径)
    test_files = ['/etc/passwd']  # 示例文件
    
    for file_path in test_files:
        if os.path.exists(file_path):
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding
The skill advertises local file handling and references reading a sensitive config file, but it does not declare any tool scope such as permissions or allowed-tools. In an agent environment, missing explicit scope weakens sandboxing and user visibility, increasing the chance of unintended file reads or broader access than expected.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill describes file upload features but does not clearly warn users that local files may be transmitted to a remote cloud service. In a conversational agent context, missing consent and data-transfer warnings increase the risk of users unintentionally sending sensitive local content to external storage.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The OpenClaw integration text says the skill can be triggered via the message system and used as a media processor, but it does not define narrow activation criteria or user-confirmation boundaries. Broad trigger language can cause accidental invocation on arbitrary files or conversations, especially for a skill that may access local files and transmit data remotely.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def __init__(self, config_path: str = "/root/.openclaw/aliyun-oss-config.json"):
        self.config_path = config_path
        self.config = self.load_config()
        self.auth = None
        self.bucket = None
        self.init_oss_client()
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code reads a local file and sends it to Alibaba Cloud OSS via `put_object`, and may also change the object ACL to public-read. Although the module docstring says it is an upload tool, there is no inline user disclosure at the point of transfer or before making content public, beyond a terse parameter note.

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Content
else:
                # 小文件直接上传
                with open(local_file, 'rb') as f:
                    self.bucket.put_object(oss_key, f)
                result = {"key": oss_key, "etag": "small_file"}
            
            # 设置公共读权限(如果需要)
Confidence
55% confidence
Finding
Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The upload path can optionally change an object ACL to public-read, which can expose uploaded data to anyone with the resulting URL and expands access beyond temporary signed-link sharing. In a file-upload utility, this materially increases the risk of accidental data disclosure, especially if callers set the flag without understanding the permanence and breadth of public access.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The large-file path initializes a multipart upload and repeatedly uploads file parts to OSS, but this path has no confirmation prompt or user-facing warning about transmitting potentially sensitive local data to a remote service. The surrounding comments are implementation-focused and do not disclose privacy or data-handling impact.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes the skill as a file upload tool and temporary link generator, which naturally covers uploading objects and generating presigned URLs. However, this function enumerates existing bucket contents and searches for matching object names, expanding the behavior into remote listing/discovery rather than just upload/link generation.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The top-level docstring says the skill uploads files and returns a temporary access link, and the function docstring repeats that the return value is a temporary link or error. However, the code at L37-L42 constructs a normal object URL and explicitly tells the user to use the OSS console to generate a temporary link later, which contradicts the documented behavior.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The function uploads a user-supplied file to an external cloud storage service without any explicit consent prompt, warning, or confirmation that data will leave the local environment. In an agent skill context, this can lead to unintended exfiltration of sensitive files if a user or upstream agent assumes processing is local-only.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest describes the skill as an OSS upload tool with temporary link generation. In this implementation, successful execution only reports the OSS path and a standard URL, then asks the user to generate the temporary access link in the OSS console, so the advertised temporary-link capability is not actually performed here.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code exposes its description, usage text, and command help entirely in Chinese, which imposes a specific language on users without any visible opt-in or alternative. Under the policy, language-only behavior is a natural-language policy violation unless the locale restriction is explicitly justified or a choice is offered.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The module docstring is entirely in Chinese, including the functional description, with no indication that language selection is optional or that the skill is limited to a Chinese-speaking environment. This creates a natural-language locale policy issue because the skill implicitly fixes one language without user opt-in or justification.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The function is documented and named as if it enforces least-privilege OSS permissions, but in practice it only checks whether a security token exists and then returns success. This can create a false sense of security and allow overprivileged or misconfigured credentials to be treated as safe, increasing the risk of unauthorized object access or bucket misuse.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The function retrieves `access_key_id` and `access_key_secret`, which are sensitive credentials, but the file provides no user-facing warning, logging, confirmation, or explanatory comment about handling secrets. For code files, access to sensitive credentials should include some form of disclosure unless clearly documented elsewhere, which is not evident in this file.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The module docstring and function docstring are written only in Chinese, and there is no visible indication that the skill supports other languages or that Chinese is a required locale. This creates a natural-language policy concern because the file imposes a specific language without user opt-in or documented justification.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
Natural-language strings including the module description, help text, and error messages are all Chinese, with no indication that users may choose another language. This can violate a language/locale policy when a skill imposes one language by default without opt-in.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The top-level docstring is entirely in Chinese and presents the skill's purpose only in that language. Under the policy, forcing a specific language without user opt-in or a documented regional justification is a natural-language policy concern.

Static analysis

No suspicious patterns detected.