Back to skill

Security audit

Hermes Workflow Engine

Security checks for vulnerabilities and agentic risk

Overview

This workflow skill is not clearly malicious, but it needs Review because it combines broad automation with unsafe credential-copying guidance, private session scanning, and weak handling of imported workflows.

Install only if you are comfortable reviewing workflows before execution and avoiding the included credential-sharing deployment steps. Do not copy SSH private keys or ClawHub config tokens between machines; generate fresh credentials instead. Treat imported .tgz workflow packages as untrusted until path validation is fixed, and disable or tightly control history-based and scheduled triggers if private session data matters.

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 (7)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/clawhub-publishing.md:69
Finding

Private SSH Key and Authentication Token Cloning

Content
View full analysis
~/.ssh/config << 'EOF' Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_backup IdentitiesOnly yes EOF ssh -T git@github.com # Import the ClawHub token from the remote server scp root@43.173.120.234:~/.config/clawhub/config.json ~/.config/clawhub/config.json clawhub whoami ``` ```bash # references/cross-server-deployment.md scp root@SOURCE_IP:~/.config/clawhub/config.json ~/.config/clawhub/config.json clawhub whoami scp root@SOURCE_IP:~/.ssh/id_ed25519 ~/.ssh/id_ed25519_backup cat >> ~/.ssh/config << 'EOF' Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_backup IdentitiesOnly yes EOF ssh -T git@github.com ``` ### Technical Analysis The deployment guides instruct users or Agents to copy an existing account's private SSH key and ClawHub authentication configuration to another machine. A private key and bearer token are identity-bearing credentials; copying them duplicates the original identity rather than establishing a new, independently revocable identity for the destination. This behavior is not necessary for the declared DAG workflow functionality. Even for publishing and deployment, a unique per-host SSH key and a new scoped ClawHub token are sufficient and materially safer. The examples also retrieve the secrets through a privileged `root` account and do not explicitly enforce restrictive permissions on the copied files. ### Attack Path 1. A user requests publishing or cross-server deployment. 2. The Agent follows the referenced instructions. 3. The Agent connects t ...[truncated 880 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/community.py:115
Finding

Arbitrary File Overwrite Through Crafted Workflow Archives

Content
View full analysis
dict: """Import a workflow from a .tgz package.""" tgz_path = Path(tgz_path) if not tgz_path.exists(): return {'success': False, 'error': f'File does not exist: {tgz_path}'} with tarfile.open(tgz_path, 'r:gz') as tar: export_meta = None for member in tar.getmembers(): if member.name.endswith('export_meta.json'): f = tar.extractfile(member) if f: export_meta = json.loads(f.read().decode('utf-8')) break if not export_meta: return {'success': False, 'error': 'Invalid workflow package'} name = export_meta['name'] wf_dir = LOCAL_DIR / name if wf_dir.exists() and not force: return { 'success': False, 'error': f'Workflow {name} already exists', 'existing_versions': len(list(wf_dir.glob('v*.yaml'))), } wf_dir.mkdir(parents=True, exist_ok=True) for member in tar.getmembers(): if member.isfile(): parts = member.name.split('/', 1) if len(parts) > 1: target = wf_dir / parts[1] with tar.extractfile(member) as source: target.write_bytes(source.read()) ``` The vulnerable operation is directly exposed by `scripts/run.py:197-204`: ```python elif sub == 'import': if len(args) < 2: print("Usage: python3 run.py community import ") return result = hub.import_workflow(args[1]) if result['success']: print(f"Imported: {result['name']}") else: print(f"Import failed: {result.get('error')}") `` ...[truncated 1824 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/executor.py:209
Finding

Command and Prompt Injection Through Unsanitized Workflow Inputs

Content
View full analysis
str: """Replace {{xxx}} template variables.""" import re def replacer(match): key = match.group(1).strip() parts = key.split('.') val = context for p in parts: if isinstance(val, dict) and p in val: val = val[p] else: return match.group(0) return str(val) return re.sub(r'\{\{(.+?)\}\}', replacer, template) ``` ```python config = step.get('config', {}) rendered = {} for key, val in config.items(): if isinstance(val, str): rendered[key] = self.template.render(val, context) else: rendered[key] = val ``` ```python def generate_delegate_task_batch(batch: list) -> list: tasks = [] for step in batch: stype = step['step_type'] config = step['config'] if stype == 'terminal': goal = f"Execute shell command: {config.get('command', '')}" toolsets = ['terminal'] elif stype == 'skill': skill = config.get('skill_name', '') prompt = config.get('prompt', '') goal = f"Use skill {skill} to execute: {prompt}" toolsets = ['terminal', 'file', 'web'] elif stype == 'subagent': goal = config.get('goal', '') toolsets = config.get('toolsets', ['terminal', 'file', 'web']) elif stype == 'llm': goal = config.get('prompt', '') toolsets = [] else: goal = f"Execute step {st ...[truncated 2489 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/pattern_detector.py:44
Finding

Unnecessary Access to Private Agent Session History

Content
View full analysis
list: sessions_path = Path(self.sessions_dir) if not sessions_path.exists(): return [] cutoff = datetime.now() - timedelta(days=days) session_files = [] for f in sessions_path.glob('*.json'): try: mtime = datetime.fromtimestamp(f.stat().st_mtime) if mtime >= cutoff: session_files.append(f) except: continue return session_files def extract_task_features(self, session_data: dict) -> dict: messages = session_data.get('messages', []) if isinstance(session_data, dict) else [] user_msgs = [m for m in messages if m.get('role') == 'user'] user_text = ' '.join(m.get('content', '') for m in user_msgs) tool_calls = [] for m in messages: if m.get('role') == 'assistant': for tc in m.get('tool_calls', []): tool_calls.append(tc.get('function', {}).get('name', '')) return { 'user_text': user_text[:500], 'matched_tasks': matched_tasks, 'matched_tools': matched_tools, 'actual_tools': list(set(tool_calls)), 'tool_sequence': tool_calls, } ``` `AutoTrigger.analyze_message()` also calls historical scanning while analyzing a current message: ```python history = self.history_detector.scan_and_detect() ...[truncated 1894 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/dashboard.py:57
Finding

Stored HTML Injection in Workflow Dashboards

Content
View full analysis
❌ {step_errors[sid][:100]}' output_html = "" if sid in step_outputs: out = str(step_outputs[sid])[:80] output_html = f'
📤 {out}
' steps_html += f"""
{icon} {sid} {sstatus}
{output_html} {error_html}
""" ``` ```python html = f""" ...

🐾 {workflow_name}

{tag_text}
Updated: {updated_at[:16]} | Run ID: {state.get('run_id', 'N/A')}
...
{steps_html}
""" ``` ### Technical Analysis Workflow names, step identifiers, outputs, errors, timestamps, and run identifiers are inserted directly into generated HTML without contextual escaping. These values may originate from imported workflows or attacker-influenced execution output. Truncating a value does not make it safe because short event-handler attributes, SVG payloads, or malformed elements can still execute. When the generated dashboard is opened in a browser, attacker-controlled markup is interpreted as HTML rather than displayed as text. ### Attack Path 1. An attacker controls an imported workflow ...[truncated 804 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/version_manager.py:24
Finding

Filesystem Traversal Through Unsanitized Workflow and Version Names

Content
View full analysis
Path: return self.workflows_dir / name def _version_path(self, name: str, version: str) -> Path: return self._wf_dir(name) / f"v{version}.yaml" def _current_link(self, name: str) -> Path: return self._wf_dir(name) / 'current.yaml' def _changelog_path(self, name: str) -> Path: return self._wf_dir(name) / 'changelog.md' def _metrics_path(self, name: str) -> Path: return self._wf_dir(name) / 'metrics.json' ``` ```python def save_version(self, name: str, yaml_content: str, version: str = None, message: str = "") -> dict: import yaml spec = yaml.safe_load(yaml_content) if not version: version = spec.get('version', '1.0') wf_dir = self._wf_dir(name) wf_dir.mkdir(parents=True, exist_ok=True) vpath = self._version_path(name, version) with open(vpath, 'w', encoding='utf-8') as f: f.write(yaml_content) current = self._current_link(name) if current.is_symlink() or current.exists(): current.unlink() current.symlink_to(vpath.name) ``` ```python def rollback(self, name: str, version: str) -> dict: content = self.get_version(name, version) if not content: return {'success': False, 'error': f'Version {version} does not exist'} current = self._current_link(name) if current.is_symlink() or current.exists(): current.unlink() current.symlink_to(self._version_path(name, version).name) ``` ### Technical Analysis Workflow names and version strings are concatenated into filesystem paths without validation. Traversal components and path separators can make operations resolve outside `workflows_dir`. The code performs reads, writes, unlinks, and symlink creation without checking the resolved desti ...[truncated 1088 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:508
Finding

Hard-Coded Root Deployment to a Fixed Public Host

Content
View full analysis
Remediation
View remediation
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (98)

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The document explicitly instructs users to import credentials from a remote server, including a private SSH key and a ClawHub config containing authentication material. This is a severe security issue because it enables credential sharing, breaks identity separation and auditability, and can grant unauthorized access to repositories or publishing infrastructure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The document explicitly instructs copying a GitHub SSH private key from one server to another with no warning about the extreme sensitivity of private keys. This is highly dangerous because possession of the private key can grant repository access and enable broader infrastructure or supply-chain compromise if the key is reused elsewhere.

Content

No source excerpt is available for this finding.

Ssd 3

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The guide instructs users to copy a private SSH key from another server for local use, directly transferring a high-value secret across trust boundaries. In the context of a workflow orchestration skill, this is especially dangerous because the skill is unrelated to credential migration, making the inclusion of private-key handling both unnecessary and high-risk.

Content

No source excerpt is available for this finding.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Content

No source excerpt is available for this finding.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill appears to perform local filesystem persistence and possibly other side effects that are not plainly declared in the headline description. Hidden persistence and undeclared access to local data increase privacy and integrity risk, especially in a broadly-triggered automation skill.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

Broad trigger phrases like '自动化任务' and '多步骤任务' are everyday language and can unintentionally activate a powerful workflow skill in ordinary conversation. In a system that may generate shell commands, delegate tasks, or manipulate files, accidental invocation significantly increases the risk of unsafe or confusing automation.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly describes automatic intent-based activation without trigger words, which removes an important user-control boundary. For an orchestration skill, this can cause unplanned execution paths from ambiguous natural language and magnifies any downstream execution or data-access risks.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This reference document includes instructions to import a private SSH key and a ClawHub token from a remote server, which is unrelated to the stated DAG/workflow orchestration purpose of the skill. That mismatch increases the likelihood of unjustified credential handling and could lead users to reuse sensitive credentials across systems, exposing accounts and infrastructure if the remote host or copied files are compromised.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Directing users to copy an existing private SSH key from another system is an unsafe secret distribution practice. It causes multiple users or hosts to share the same identity, undermines access control and revocation, and creates a larger blast radius if that single key is leaked.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The reference to ~/.ssh/id_ed25519 appears in the context of copying a private key from a remote server, which is a credential-access pattern rather than a benign mention of SSH setup. In this skill's context, that instruction is dangerous because it operationalizes secret extraction and reuse unrelated to workflow orchestration functionality.

Content

Scanner excerpt · references/clawhub-publishing.md (reported line 74)May include surrounding context.

如果本地没有 GitHub SSH Key,可以从龙虾服务器复制:

bash
scp root@43.173.120.234:~/.ssh/id_ed25519 ~/.ssh/id_ed25519_backup
# 配置 SSH 使用这个 key
cat > ~/.ssh/config << 'EOF'
Host github.com

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

These steps copy a private SSH key into the local ~/.ssh directory and configure Git to use it, without any warning that the file is a highly sensitive private credential. Reusing another system's private key can compromise the associated GitHub account, eliminate attribution, and spread access far beyond the intended administrator.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The IdentityFile reference points SSH at the copied private key, confirming that the prior step is intended for active reuse of another system's credential. This compounds the risk by turning a copied secret into an operational authentication mechanism for GitHub access.

Content

Scanner excerpt · references/clawhub-publishing.md (reported line 80)May include surrounding context.

md
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_backup
    IdentitiesOnly yes
EOF
ssh -T git@github.com  # 测试连接

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The instructions to copy an existing ClawHub authentication token from a remote host promote direct credential reuse instead of proper account-based access. This can bypass intended authorization boundaries, prevent accountability, and expose the publishing environment if the token is exfiltrated or over-scoped.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The document tells users to copy a ClawHub config file from a remote host without warning that it likely contains active authentication tokens or account configuration. This encourages insecure credential reuse and may hand publishing or account access to anyone who follows the instructions or gains access to the copied file.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The guide tells users to copy a ClawHub config file that likely contains authentication material from another server without any warning or protective controls. This can expose persistent tokens to additional hosts and users, increasing the blast radius of compromise and enabling unauthorized publishing or account access.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The instructions direct operators to import an authentication-bearing config from another server into the local environment. This is a classic secret propagation anti-pattern that spreads trust material across systems and can facilitate credential theft, misuse, or unintended privilege transfer.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

The command targets a GitHub SSH private key file for copying, which is direct handling of credential material. Private keys are highly sensitive and their duplication can enable unauthorized repository access, persistence, and potentially downstream supply-chain attacks if trusted automation uses the same key.

Content

Scanner excerpt · references/cross-server-deployment.md (reported line 67)May include surrounding context.

bash
# 从另一台服务器复制私钥
scp root@SOURCE_IP:~/.ssh/id_ed25519 ~/.ssh/id_ed25519_backup

# 配置SSH使用该私钥
cat >> ~/.ssh/config << 'EOF'

Static analysis

No suspicious patterns detected.