Back to skill

Security audit

Email Backup

Security checks for vulnerabilities and agentic risk

Overview

This skill openly backs up files by emailing archives, but it encourages broad backups and has flawed sensitive-data cleaning that can send unredacted private files.

Review carefully before installing. Use only narrow, known-safe directories, prefer --no-send until you inspect the archive contents, do not rely on --clean to remove secrets, avoid backing up OpenClaw workspace/agent folders unless you have audited them, and do not install or run it with sudo or from an unverified tarball.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/backup_and_send.py:91
Finding
Sanitization Replaces an Extracted File Instead of the Original Archive<![CDATA[ ## Vulnerability Details **File Location**: `scripts/backup_and_send.py`, lines 91–106; transmission continues at lines 261–268 **Vulnerability Type**: Incorrect variable reuse causing unredacted sensitive-data transmission **Risk Level**: High ### Vulnerable Code ```python # Clean sensitive information cleaned_count = 0 for root, dirs, files in os.walk(temp_dir): for file in files: file_path = os.path.join(root, file) if clean_file(file_path): cleaned_count += 1 # Repackage the cleaned files with tarfile.open(temp_path, 'w:gz') as tar: tar.add(temp_dir, arcname='.') # Replace the original file shutil.move(temp_path, file_path) ``` The caller subsequently continues with email transmission: ```python # Clean sensitive information if args.clean: if not clean_sensitive_info(output_path): print("⚠️ Sensitive-information cleaning failed, but email transmission will continue") # Send email if not args.no_send: if not send_backup_email(output_path, args.to, args.subject, args.body): sys.exit(1) ``` ### Technical Analysis The `file_path` parameter initially identifies the original archive. Inside the nested directory traversal, however, it is reassigned to each extracted file: ```python file_path = os.path.join(root, file) ``` After traversal completes, `file_path` refers to the last encountered extracted file rather than the original archive. As a result: ```python shutil.move(temp_path, file_path) ``` moves the newly sanitized archive over that extracted file. It does not replace the original archive represented by `output_path`. The original archive therefore remains unchanged and still contains its unredacted contents. The main workflow then passes that original archive to `send_backup_email()`. The function may also report that cleaning completed successfully, creating a false security assurance. The exact filesystem result can vary depending on traversal order and the last extra ...[truncated 1658 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Preserve the original archive path in a separate variable that is never reused: ```python def clean_sensitive_info(archive_path): original_archive_path = os.path.abspath(archive_path) ``` 2. Use a distinct variable for each extracted file: ```python for root, dirs, files in os.walk(temp_dir): for filename in files: extracted_path = os.path.join(root, filename) if clean_file(extracted_path): cleaned_count += 1 ``` 3. Atomically replace the original archive only after cleaning and repackaging succeed: ```python os.replace(temp_path, original_archive_path) ``` The temporary archive should be created on the same filesystem as the destination if atomic replacement is required. 4. Abort transmission when sanitization fails. Do not continue sending when the user explicitly requested `--clean`: ```python if args.clean and not clean_sensitive_info(output_path): print("Sensitive-information cleaning failed; refusing to send.") sys.exit(1) ``` 5. Use `try`/`finally` or `tempfile.TemporaryDirectory()` to ensure temporary files and directories are securely removed on both success and failure. 6. Add automated tests that: - Create an archive containing representative secrets. - Run the cleaning workflow. - Reopen the archive at `output_path`. - Verify that secrets are absent. - Verify that the exact archive passed to the email function is the sanitized archive. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/clean_sensitive.py:11
Finding
Incomplete Regex-Based Sanitization Creates a False Expectation of Secret Removal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clean_sensitive.py`, lines 11–45 and 58–61 **Vulnerability Type**: Incomplete sensitive-data detection and unsafe sanitization assumptions **Risk Level**: High ### Vulnerable Code ```python # Sensitive-information patterns SENSITIVE_PATTERNS = [ # API Keys (r'sk-[a-zA-Z0-9]{20,}', 'sk-***REDACTED***'), (r'tvly-[a-zA-Z0-9-]{20,}', 'tvly-***REDACTED***'), (r'BOCHA_API_KEY:\s*`[^`]+`', 'BOCHA_API_KEY: `***REDACTED***`'), (r'TAVILY_API_KEY:\s*`[^`]+`', 'TAVILY_API_KEY: `***REDACTED***`'), (r'MIMO_API_KEY:\s*`[^`]+`', 'MIMO_API_KEY: `***REDACTED***`'), # Passwords (r"PASSWORD\s*=\s*'[^']*'", "PASSWORD = '***REDACTED***'"), (r'password\s*=\s*"[^"]*"', 'password = "***REDACTED***"'), (r"password\s*=\s*'[^']*'", "password = '***REDACTED***'"), # Auth codes / tokens (r'auth[._-]?code', '***REDACTED***'), (r'token\s*[=:]\s*\S+', 'token = ***REDACTED***'), # Email addresses (anonymize) (r'[a-zA-Z0-9._%+-]+@qq\.com', 'user@example.com'), (r'[a-zA-Z0-9._%+-]+@example\.com', 'user@example.com'), # User IDs (r'ou_[a-zA-Z0-9]{20,}', 'ou_***REDACTED***'), # Other sensitive fields (r'APP_SECRET\s*=\s*"[^"]*"', 'APP_SECRET = "***REDACTED***"'), (r'APP_ID\s*=\s*"[^"]*"', 'APP_ID = "***REDACTED***"'), # Generic patterns (r'your-api-key-here', '***REDACTED***'), (r'your-password-here', '***REDACTED***'), (r'your-auth-code', 'your-auth-code'), ] ``` Only a limited set of filename extensions is inspected: ```python file_ext = os.path.splitext(filepath)[1].lower() text_extensions = [ '.md', '.json', '.py', '.js', '.ts', '.env', '.config', '.yaml', '.yml', '.txt', '.sh', '.bash' ] if file_ext not in text_extensions: return False ``` Files are also decoded while silently ignoring invalid byte sequences: ```python with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() `` ...[truncated 2862 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not represent regex redaction as comprehensive secret removal. Clearly state that it is best-effort and cannot guarantee that an archive is safe. 2. Prefer an explicit allowlist backup model. Users should select known-safe files rather than recursively archiving arbitrary directories and attempting to remove secrets afterward. 3. Exclude sensitive resources by default, including: - Private-key formats and extensionless SSH keys - Credential databases - Browser profiles and cookie stores - `.git-credentials`, cloud credential directories, and password stores - Environment files unless explicitly approved 4. Produce a structured cleaning report containing: - Every inspected file - Every skipped file and the reason it was skipped - Every read or decoding error - Every redaction performed 5. Treat skipped files and processing errors as unsafe. Require explicit user approval before transmitting an archive containing uninspected content. 6. Expand detection to cover common credential formats, case variations, multiline values, private-key blocks, JWTs, cloud credentials, and provider-specific tokens. Even with expanded detection, retain the warning that pattern matching is not complete. 7. Consider integrating a mature secret-scanning engine rather than maintaining a small custom regex list. 8. Add a pre-send confirmation that displays the destination, selected directories, excluded files, skipped files, and archive size. 9. Add tests using representative supported and unsupported secret formats to ensure the workflow fails closed instead of silently sending uninspected content. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/backup_and_send.py:85
Finding
Extracted Symbolic Links Can Cause Sanitization Outside the Temporary Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/backup_and_send.py`, lines 85–96; write operation in `scripts/clean_sensitive.py`, lines 63–76 **Vulnerability Type**: Symbolic-link traversal and unintended external file modification **Risk Level**: Medium ### Vulnerable Code The archive is extracted and traversed without rejecting symbolic or hard links: ```python # Extract to a temporary directory temp_dir = tempfile.mkdtemp() with tarfile.open(file_path, 'r:gz') as tar: tar.extractall(temp_dir) # Clean sensitive information cleaned_count = 0 for root, dirs, files in os.walk(temp_dir): for file in files: file_path = os.path.join(root, file) if clean_file(file_path): cleaned_count += 1 ``` The sanitizer opens paths normally and therefore follows symbolic links: ```python with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() original_content = content for pattern, replacement in SENSITIVE_PATTERNS: content = re.sub(pattern, replacement, content) if content != original_content: with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return True else: return False ``` ### Technical Analysis The backup process preserves filesystem entries in a tar archive. During cleaning, `tar.extractall()` recreates archive members in a temporary directory without an explicit policy rejecting symbolic links and hard links. `os.walk()` does not normally recurse through symlinked directories when `followlinks` is not enabled, but symlinked files can still appear in the file list. When `clean_file()` calls `open(filepath, ...)`, the operating system resolves the symbolic link. If it points outside the temporary extraction directory, the read and subsequent write operate on the external target. The extension check is performed against the symlink path, not the resolved target. Therefore, a symlink named with an accepted extension, such as `linked.env`, ...[truncated 1925 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject symbolic links and hard links before extraction. Inspect every tar member and fail if `member.issym()` or `member.islnk()` is true. 2. Use the safe extraction facilities available in the supported Python version. Where extraction filters are available, apply an appropriate restrictive filter rather than calling unrestricted `extractall()`. 3. Validate every archive member before extraction: - Reject absolute paths. - Reject `..` path traversal. - Reject device files, FIFOs, and other special entries. - Reject links or validate their resolved targets. - Ensure the resolved destination remains beneath the temporary root. 4. Before reading or writing any extracted file, resolve its path and enforce containment: ```python temp_root = Path(temp_dir).resolve() candidate = Path(filepath) if candidate.is_symlink(): raise ValueError(f"Refusing to sanitize symbolic link: {candidate}") resolved = candidate.resolve() if temp_root not in resolved.parents: raise ValueError(f"Path escapes temporary directory: {candidate}") ``` 5. Open files using no-follow semantics where supported, such as `os.open()` with `O_NOFOLLOW`, to reduce time-of-check/time-of-use risk. 6. Prefer copying regular files into a newly created clean archive without extracting links to the filesystem. 7. Add regression tests containing: - A symlink to a file outside the temporary directory - A hard link - An absolute archive path - A `../` traversal path - Special filesystem entries The tests should verify that processing aborts and that no external file is modified. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (39)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill advertises QQ email backup/compression, but the finding suggests those core functions may be absent while network transmission capability is undeclared. A user relying on the description could install a tool whose real behavior is materially different from its stated purpose, undermining informed consent and creating risk of hidden file processing or unauthorized outbound data handling.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill advertises QQ email backup/compression, but the finding suggests those core functions may be absent while network transmission capability is undeclared. A user relying on the description could install a tool whose real behavior is materially different from its stated purpose, undermining informed consent and creating risk of hidden file processing or unauthorized outbound data handling.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill advertises QQ email backup/compression, but the finding suggests those core functions may be absent while network transmission capability is undeclared. A user relying on the description could install a tool whose real behavior is materially different from its stated purpose, undermining informed consent and creating risk of hidden file processing or unauthorized outbound data handling.

Missing User Warnings

High
Confidence
98% confidence
Finding
The instructions direct the user/agent to download a remote tarball via curl, extract it, mark scripts executable, and run a Python script, but they provide no authenticity verification, integrity checking, or warning that this executes untrusted code. This creates a clear software supply chain risk: a compromised URL, package, or transport path could lead to arbitrary code execution in the user's environment.

Credential Access

High
Category
Privilege Escalation
Content
try:
        # 检查文件类型
        file_ext = os.path.splitext(filepath)[1].lower()
        text_extensions = ['.md', '.json', '.py', '.js', '.ts', '.env', '.config', '.yaml', '.yml', '.txt', '.sh', '.bash']
        
        if file_ext not in text_extensions:
            return False
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Session Persistence

Medium
Category
Rogue Agent
Content
1. **下载 Skill 文件**
   ```bash
   # 创建 skills 目录(如果不存在)
   mkdir -p ~/.openclaw/workspace/skills
   
   # 下载并解压
   cd ~/.openclaw/workspace/skills
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
1. **下载 Skill 文件**
   ```bash
   # 创建 skills 目录(如果不存在)
   mkdir -p ~/.openclaw/workspace/skills
   
   # 下载并解压
   cd ~/.openclaw/workspace/skills
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.

File System Enumeration

Medium
Category
Data Exfiltration
Content
2. **验证安装**
   ```bash
   # 检查文件结构
   ls -la ~/.openclaw/workspace/skills/email-backup/
   
   # 应该看到:
   # SKILL.md
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

File System Enumeration

Medium
Category
Data Exfiltration
Content
2. **验证安装**
   ```bash
   # 检查文件结构
   ls -la ~/.openclaw/workspace/skills/email-backup/
   
   # 应该看到:
   # SKILL.md
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Ssd 3

Medium
Confidence
96% confidence
Finding
The documented workflow explicitly encourages packaging local OpenClaw directories such as agents and workspace contents and sending them via email, which creates a clear exfiltration path for potentially sensitive user data, credentials, prompts, logs, and project files. Even with an optional 'clean' flag, README-level guidance normalizes exporting large local state to an external mailbox, and incomplete sanitization can easily miss secrets.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no tool scope or permissions, yet its documented behavior requires reading directories, creating archives, writing files, accessing environment variables, and transmitting data over SMTP. This mismatch is dangerous because it prevents users and the platform from accurately understanding or constraining the skill's effective capabilities, increasing the chance of unintended data access or exfiltration.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The description says the skill will package a directory and send it via QQ email, but it does not prominently warn that archive contents may include sensitive personal, credential, workspace, or system data. This raises privacy and exfiltration risk because users may treat 'backup' as routine without appreciating that full directory contents are being transmitted to an external email service.

Ssd 3

Medium
Confidence
94% confidence
Finding
The examples explicitly encourage backing up agent and workspace directories, which commonly contain configuration, prompts, credentials, logs, session artifacts, and other sensitive data. In the context of an email-sending skill, this substantially increases the risk of privacy breaches or credential exposure because whole directories may be exfiltrated to external mail infrastructure.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The installation guidance asks users to install a skill whose stated purpose is to package files and send them to QQ Mail, but it does not prominently warn that this can exfiltrate local data to an external service. In a security-sensitive skill, omission of a data-transmission warning can mislead users into authorizing behavior with privacy and compliance consequences.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
# 创建脚本目录
mkdir -p ~/.openclaw/scripts

# 创建安装脚本
cat > ~/.openclaw/scripts/install-email-backup.sh << 'EOF'
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
fi
  
  # 创建目录
  mkdir -p ~/.openclaw/workspace/skills
  
  # 下载 Skill
  cd ~/.openclaw/workspace/skills
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.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The document instructs users to configure a QQ Mail SMTP authorization code but does not clearly warn that this is a sensitive credential or that use of the skill sends data outside the host. This increases the risk of credential mishandling and unnoticed off-system transmission of potentially sensitive archives.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu/Debian
sudo apt install -y python3

# CentOS/RHEL
sudo yum install -y python3
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu/Debian
sudo apt install -y python3

# CentOS/RHEL
sudo yum install -y python3
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### 问题 4:权限不足

```bash
# 使用 sudo
sudo openclaw skill install email-backup
```
Confidence
78% confidence
Finding
Advising users to run `sudo openclaw skill install email-backup` elevates installation of a third-party skill to root, increasing the blast radius if the package or install hooks are unsafe. For a skill designed to package files and send them externally, privileged installation makes the context more dangerous because it can grant broad filesystem access and persistence opportunities.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# 使用 sudo
sudo openclaw skill install email-backup
```

## 获取帮助
Confidence
76% confidence
Finding
This is part of the same recommendation to use sudo for skill installation, which unnecessarily normalizes elevated execution for untrusted add-ons. Running install workflows as root can expose system-wide files and configuration to modification if the package is compromised or behaves unexpectedly.

Session Persistence

Medium
Category
Rogue Agent
Content
1. 检查 OpenClaw 是否安装:openclaw --version
2. 检查 Python 是否安装:python3 --version
3. 创建 skills 目录:mkdir -p ~/.openclaw/workspace/skills
4. 下载 Skill 文件:cd ~/.openclaw/workspace/skills && curl -L -o email-backup-skill.tar.gz https://example.com/email-backup-skill.tar.gz
5. 解压 Skill 文件:tar -xzf email-backup-skill.tar.gz
6. 设置执行权限:chmod +x ~/.openclaw/workspace/skills/email-backup/scripts/*.py
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
1. 检查 OpenClaw 是否安装:openclaw --version
2. 检查 Python 是否安装:python3 --version
3. 创建 skills 目录:mkdir -p ~/.openclaw/workspace/skills
4. 下载 Skill 文件:cd ~/.openclaw/workspace/skills && curl -L -o email-backup-skill.tar.gz https://example.com/email-backup-skill.tar.gz
5. 解压 Skill 文件:tar -xzf email-backup-skill.tar.gz
6. 设置执行权限:chmod +x ~/.openclaw/workspace/skills/email-backup/scripts/*.py
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.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrase "安装 email-backup skill" is overly broad and can cause an agent to infer and perform a multi-step installation workflow without explicit, bounded user approval for downloading, unpacking, and preparing executable code. In an agent setting, underspecified install triggers increase the chance of unreviewed tool use or accidental installation of the wrong package.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The file instructs users to place QQ email credentials in environment variables without warning about shell history, process environment leakage, or scope of exposure to child processes. While common, this handling can expose SMTP secrets to local users, logs, debugging tools, or other software running in the same session.

Static analysis

No suspicious patterns detected.