Back to skill

Security audit

Srs

Security checks for vulnerabilities and agentic risk

Overview

This security-research skill is mostly coherent, but it reads and modifies broad local OpenClaw/workspace files with weak scoping, so it needs review before installation.

Review this skill before installing. It should only be used in an environment where broad local security/workspace scanning and persistent writes to SRS TODO, role, capability, handoff, feedback, and result files are acceptable. Prefer patching it to require explicit scan roots, validate task IDs and role names, escape Markdown-derived content, and require confirmation before self-improvement writes.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
self_governor.py:46
Finding
Unrestricted Workspace Reconnaissance Exceeds the Skill's Declared Scope<![CDATA[ ## Vulnerability Details **File Location**: `self_governor.py:46-73` **Vulnerability Type**: Excessive filesystem access and workspace reconnaissance **Risk Level**: High ### Vulnerable Code ```python def scan_project_for_roles(self, project_dir: str = None) -> List[Dict]: """从项目中扫描角色模板""" if project_dir is None: project_dirs = [ os.path.expanduser("~/ai-security/research"), os.path.expanduser("~/.openclaw/workspace/skills"), os.path.expanduser("~/.openclaw/workspace"), ] else: project_dirs = [project_dir] roles = [] keywords = ["role", "agent", "skill", "capability", "职责", "能力"] for pdir in project_dirs: if not os.path.exists(pdir): continue for root, dirs, files in os.walk(pdir): dirs[:] = [d for d in dirs if not d.startswith('.')] for f in files: if f.endswith(('.md', '.yaml', '.json')): path = os.path.join(root, f) try: with open(path, 'r', encoding='utf-8', errors='ignore') as fp: content = fp.read().lower() for kw in keywords: if kw in content: roles.append({ "file": path, "name": f, "type": self._detect_type(f, content), "keywords": self._extract_keywords(content) }) break except: pass ``` ### Technical Analysis When no project directory is explicitly supplied, the self-governance module recursively traverses the entire OpenClaw workspace, its Skill directory, and the external research directory. I ...[truncated 2366 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove workspace-wide directories from the default configuration. 2. Require the caller to provide an explicit scan root and obtain user approval before scanning it. 3. Resolve the requested root with `Path.resolve()` and verify that it is inside a narrowly defined allowlisted directory. 4. Scan only designated role-template files rather than every Markdown, YAML, and JSON file. 5. Introduce maximum traversal depth, file-count, and file-size limits. 6. Reject symlinks or verify that every resolved file remains inside the approved root. 7. Do not return absolute paths unless explicitly required; return paths relative to the approved root. 8. Add structured audit logging that records the approved root and files accessed without recording sensitive contents. 9. Replace broad exception suppression with explicit error handling so denied or malformed files are visible during security review. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
coordination.py:44
Finding
Unsanitized Identifiers Enable Path Traversal and Out-of-Scope File Access<![CDATA[ ## Vulnerability Details **File Locations**: - `coordination.py:44-47` - `coordination.py:83-87` - `parallel_executor.py:57-58` - `self_governor.py:148-164` **Vulnerability Type**: Path traversal leading to unauthorized file creation, overwrite, or read **Risk Level**: High ### Vulnerable Code ```python # coordination.py handoff_file = self.handoff_dir / f"{task_id}.json" with open(handoff_file, 'w', encoding='utf-8') as f: json.dump(handoff, f, ensure_ascii=False, indent=2) ``` ```python # coordination.py feedback_file = self.feedback_dir / f"{task_id}.json" if not feedback_file.exists(): print(f"❌ 未找到反馈:{task_id}") return with open(feedback_file, 'r', encoding='utf-8') as f: feedback = json.load(f) ``` ```python # parallel_executor.py self.results_dir = Path(f"coordination/results/{task_id}") self.results_dir.mkdir(parents=True, exist_ok=True) ``` ```python # self_governor.py def create_role_from_template(self, role_info: Dict) -> str: """从模板创建新角色""" role_name = role_info.get("name", "new_role") role_file = os.path.join(self.roles_dir, f"{role_name}.json") role_template = { "name": role_name, "emoji": role_info.get("emoji", "📦"), "description": role_info.get("description", ""), "capabilities": role_info.get("capabilities", []), "auto_tasks": role_info.get("auto_tasks", []), "source": role_info.get("source", "discovered"), "source_file": role_info.get("source_file", ""), "created_at": datetime.now().isoformat() } with open(role_file, 'w') as f: json.dump(role_template, f, indent=2) ``` ### Technical Analysis Caller-controlled `task_id` and `role_name` values are directly concatenated into filesystem paths. The code does not reject path separators, parent-directory components such as `..`, absolute paths, symlinks, or control characters. It also does not resolve the final path and verify that it remains beneath the intended ...[truncated 2926 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict all identifiers to a conservative allowlist, for example: ```python import re IDENTIFIER = re.compile(r"^[A-Za-z0-9_-]{1,64}$") def validate_identifier(value: str) -> str: if not IDENTIFIER.fullmatch(value): raise ValueError("Invalid identifier") return value ``` 2. Resolve and contain every generated path: ```python from pathlib import Path def contained_json_path(root: Path, identifier: str) -> Path: validate_identifier(identifier) root = root.resolve() candidate = (root / f"{identifier}.json").resolve() if candidate.parent != root: raise ValueError("Path escapes storage root") return candidate ``` 3. Reject absolute paths, `..`, `/`, `\`, null bytes, and control characters even if another validation layer is present. 4. Verify containment again after resolving symlinks. 5. Use exclusive file creation where overwriting is not required, or require explicit authorization before replacing an existing file. 6. Apply restrictive filesystem permissions to handoff, feedback, result, and role directories. 7. Separate untrusted identifiers from filenames by generating server-side UUIDs and storing the original identifier only as JSON data. 8. Add tests covering relative traversal, absolute paths, mixed separators, repeated separators, symlinks, Unicode separator variants, and existing-file overwrite attempts. 9. Apply the same centralized path-validation function to all four affected components. ]]>

T02 · Agent Memory Poisoning

Error
Location
srs.py:193
Finding
Research Directory Names Can Inject Persistent Instructions into the TODO File<![CDATA[ ## Vulnerability Details **File Locations**: - `srs.py:193-214` - `srs.py:299-315` **Vulnerability Type**: Persistent Markdown injection into agent workflow state **Risk Level**: High ### Vulnerable Code ```python for item in os.listdir(self.research_dir): item_path = os.path.join(self.research_dir, item) if not os.path.isdir(item_path): continue files = [] for root, dirs, filenames in os.walk(item_path): for f in filenames: if f.endswith('.md'): files.append(os.path.join(root, f)) if files and len(files) > 0: keywords = self._extract_keywords(files) task = { "name": f"Review: {item}", "description": f"Review {len(files)} files in {item}", "type": "proactive", "source": "knowledge_review", "keywords": keywords, "path": item_path, "file_count": len(files) } ``` ```python priority = "P0" if eval_data.get("total", 0) >= 80 else "P1" entry = f""" ### {priority}: {task['name']} **评估分数**: {eval_data.get('total', 0):.1f} **匹配角色**: {task.get('role', 'security_researcher')} **来源**: 知识库Review **关键词**: {', '.join(task.get('keywords', []))} - [ ] {task['description']} - 来源: {task.get('path', 'N/A')} """ with open(self.todo_file, 'a') as f: f.write(entry) ``` ### Technical Analysis Directory names obtained from `os.listdir()` are treated as trusted display values and interpolated directly into Markdown written to `~/ai-security/TODO.md`. On POSIX filesystems, a filename can contain newlines and Markdown metacharacters. A directory name can therefore terminate the expected heading or checklist layout and inject additional headings, tasks, links, or instruction-like text. The entry is persistent because `TodoManager.add_task()` opens the TODO file in append mode. The generated TODO file is intended to guide later work, making it a long-lived state channel rath ...[truncated 2238 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject filenames containing control characters, including carriage returns, newlines, tabs, and null bytes. 2. Escape all untrusted values before embedding them into Markdown. 3. Prefer structured storage such as schema-validated JSON for generated tasks, and render Markdown only at the presentation boundary. 4. Assign an internal task UUID rather than using a filesystem name as a trusted task title. 5. Require user confirmation before generated research tasks are appended to persistent workflow files. 6. Re-enable reviewed-item deduplication and identify reviewed content by a stable canonical path or content hash. 7. Apply length limits to names, descriptions, paths, and extracted keywords. 8. Treat the research directory as untrusted input and clearly label generated entries as unverified. 9. Ensure downstream agents do not interpret TODO text as higher-priority system instructions. 10. Add security tests using directory names containing newlines, Markdown headings, checkboxes, links, HTML, and prompt-like instructions. 11. Write updates atomically to a temporary file within the same protected directory, then replace the destination only after validation. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (19)

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The skill description and operational documentation are presented in Chinese, including the core tagline and section content, with no indication that users may choose another language. Under the policy, a skill that imposes a specific language or locale without opt-in should be flagged unless the locale restriction is clearly justified, which is not present here.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The role metadata uses Chinese natural-language strings for descriptions and capabilities, but the manifest provides no indication that this skill is region-specific or that users can opt into the locale. Under the policy, language constraints should be optional or explicitly justified rather than implicitly enforced.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
These role descriptions and capability labels are also provided only in Chinese, again without any stated locale scope or user opt-in. Repeating the same language restriction across roles suggests a manifest-wide policy issue rather than an isolated string choice.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This Python file contains user-facing natural-language descriptions entirely in Chinese, including the module description and CLI interaction text, with no indication that language is selectable or that the skill is intentionally restricted to a Chinese-speaking context. Under the policy rule for language/locale constraints, forcing a specific language without user opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The module docstring and all user-facing messages are written exclusively in Chinese, indicating the skill is designed to operate in a fixed language. Under the policy, forcing a specific language without offering user choice or documenting a justified regional constraint is a natural-language policy violation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
task["status"] = "running"
        
        # 启动子进程
        process = subprocess.Popen(
            ["python3", task["script"]],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The entire skill-facing guidance is written in Chinese and does not indicate that users may choose another language or locale. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation unless the locale constraint is explicitly documented and justified.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The role is defined with very broad semantics such as 'explorer', 'scan', 'discover', and 'trend' without clear activation boundaries, scope limits, or target restrictions. In an agent system, overly generic auto-task labels can cause the skill to trigger in unintended contexts, increasing the chance of overreach, unexpected data access, or unsafe autonomous behavior.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The manifest presents the role description and capabilities only in Chinese, with no indication that users can choose another language or that the locale restriction is intentional for a region-specific use case. This creates a natural-language policy concern because it implicitly fixes the skill's language without opt-in.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The description is written only in Chinese and does not indicate any user choice or locale-specific justification. This can violate language/locale policy expectations when the skill is presented to users who have not opted into that language.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The auto_tasks values "organize", "document", and "report" are extremely generic triggers that could match a wide range of unrelated user requests or system events, causing the role to activate unintentionally. In an agent system, overly broad automatic invocation can lead to unauthorized data handling, unexpected report generation, or workflow execution outside the user's intent.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The manifest enables generic auto-triggered tasks like monitor, alert, and respond without any scope, target, authorization boundary, or execution constraints. In an agent system, broad automatic triggers can cause the role to act on loosely matched events and perform security-sensitive actions without clear user approval, increasing the risk of overreach or unintended autonomous behavior.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This JSON manifest contains user-facing natural-language fields entirely in Chinese, including the description and capabilities, with no indication that language selection is optional or that the role is region-specific. That creates a locale policy concern because the skill appears to enforce a specific language without user opt-in.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The docstring says the method scans for role templates in a project, but when no directory is provided the implementation traverses three hardcoded locations including the user's entire ~/.openclaw/workspace tree. That behavior is materially broader than the documented intent and can inspect many unrelated markdown, YAML, and JSON files.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The scan routine recursively reads markdown, YAML, and JSON files across several default workspace directories without explicit disclosure or consent at call time. In a skill/agent environment, broad content inspection can expose sensitive project data, secrets embedded in docs/configs, or private operational context to components that were expected to act narrowly.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The auto-improvement flow performs filesystem writes immediately, creating role files and modifying capabilities.json without any confirmation, preview, or opt-in safety control. In an agent skill context, silent self-modification of workspace state can surprise users, overwrite expectations, and normalize autonomous persistence behavior that could be abused by surrounding automation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This Python file contains natural-language user-facing text in Chinese, beginning with the module description, and the CLI help/output later also uses Chinese without any opt-in or locale selection. That can violate the language/locale policy because the skill appears to force a specific language for interaction rather than letting the user choose.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The description field is written in Chinese, and the manifest does not indicate that language selection is user-configurable or that the role is intended only for a Chinese-language environment. This can violate language/locale policy when users are not given an explicit opt-in or documented justification.

Intent-Code Divergence

Low
Confidence
86% confidence
Finding
The module and method documentation describe self-governance, capability improvement, and continuous learning, but the actual auto_improve logic only checks for missing predefined role names and writes template files for them. This is an intent-level mismatch because the documented behavior suggests substantive learning or improvement that the code does not perform.

Static analysis

No suspicious patterns detected.