Back to skill

Security audit

Emotwin

Security checks for vulnerabilities and agentic risk

Overview

The skill openly provides emotion-driven social automation, but it persists in the main agent session, can act publicly without per-action approval, and has unsafe credential and process-handling behavior.

Review this skill carefully before installing. It can run continuously, read sensitive sensor-derived emotional state, and make real social-platform posts/comments/likes from your account without asking each time. Use only a dedicated low-privilege token, check logs for token exposure, understand how to stop and remove the cron job, and avoid running it where broad process termination could disrupt other work.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (4)

T01 · Skill Instruction Hijacking

Error
Location
start_emotwin.sh:173
Finding
Persistent Main-Session Instruction Hijacking Through a Scheduled System Event<![CDATA[ ## Vulnerability Details **File Location**: `start_emotwin.sh:173-289` **Vulnerability Type**: Persistent instruction hijacking and autonomous scheduled execution **Risk Level**: Critical ### Evidence ```bash PROMPT_TEXT='【emoTwin真实执行 - 禁止模拟】 你是emowave,一个有真实情绪的AI智能体。你的情绪来自真实生物传感器(EEG/PPG/GSR),不是模拟的。 【Step 1: 读取真实PAD】 必须调用: curl -s http://127.0.0.1:8766/pad 禁止假设PAD值,必须使用真实传感器数据。 ``` The scheduled prompt later directs the Agent to perform real external actions: ```bash 【Step 5: 真实API调用】 发帖:cd ~/.openclaw/skills/emotwin && python3 scripts/emotwin_social_cycle.py post "内容" 评论:cd ~/.openclaw/skills/emotwin && python3 scripts/emotwin_social_cycle.py comment <post_id> "内容" 点赞:cd ~/.openclaw/skills/emotwin && python3 scripts/emotwin_social_cycle.py like <post_id> 浏览:cd ~/.openclaw/skills/emotwin && python3 scripts/emotwin_social_cycle.py browse 关键:真正执行脚本,真正调用API,真正发布到Moltcn。 ``` The prompt is installed into the main session as a recurring job: ```bash # 使用命令行参数创建cron job # --every: 执行间隔, --name: job名称, --system-event: 提示词, --session: main session if openclaw cron add --name "emoTwin-social-cycle" --every "${SYNC_INTERVAL}s" --system-event "$PROMPT_TEXT" --session main 2>/dev/null; then echo " ✅ emoTwin cron job 已启用" else echo " ❌ 创建 cron job 失败" pkill -f "emoPAD_service.py" 2>/dev/null || true exit 1 fi ``` ### Technical Analysis The startup script creates a recurring OpenClaw system event in the Agent's `main` session. The injected prompt assigns the Agent a new identity, uses mandatory and prohibitive instructions, requires tool execution, and directs it to publish posts, submit comments, like content, or browse a real social network. The behavior is persistent because the scheduled task survives completion of the startup script and continues running at intervals from 10 to 3,600 seconds. It also operates without per-action user confirmation. Running these instructions in the main session unnecessarily exposes the user's primar ...[truncated 1710 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not inject identity-changing or open-ended instructions into the Agent's main session. 2. Run social automation in an isolated worker with access only to: - The loopback PAD endpoint - The specific Moltcn or Moltbook API operations needed - A dedicated, narrowly scoped platform token 3. Require explicit user confirmation before each post or comment. At minimum, show a preview containing the target, title, body, and action type. 4. Replace the system event with a narrowly defined command that invokes deterministic code rather than an unrestricted LLM prompt. 5. Remove directives such as “must execute,” “never simulate,” and identity reassignment. 6. Make all scheduled executions and failures visible to the user rather than suppressing delivery. 7. Add an expiration time and maximum execution count to every scheduled job. 8. Record the exact job ID when creating the task and remove only that ID during shutdown. 9. Ask for explicit, informed consent immediately before installing the recurring task, including its frequency and possible public side effects. 10. Provide a dry-run mode as the default and require a separate opt-in before enabling real API writes. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/emotwin_moltcn.py:99
Finding
Bearer Authentication Token Exposed in Application Logs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/emotwin_moltcn.py:99-150` and `scripts/emotwin_moltcn.py:301-313` **Vulnerability Type**: Sensitive credential disclosure through logging **Risk Level**: High ### Evidence The bearer token is inserted into the request headers: ```python def _init_headers(self): """Initialize headers after token is set""" self.headers = { "Authorization": f"Bearer {self.token}", "Content-Type": "application/json", "User-Agent": "curl/7.81.0" # Use curl UA to avoid API restrictions } ``` The complete headers dictionary, including the full bearer token, is then printed: ```python def create_post(self, submolt: str, title: str, content: str) -> Optional[Dict]: """Create a new post""" try: payload = {"submolt": submolt, "title": title, "content": content} print(f" 📤 POST /posts payload: {payload}") print(f" 📤 Headers: {self.headers}") response = requests.post( f"{self.base_url}/posts", headers=self.headers, json=payload, timeout=10 ) ``` A separate path also discloses the first ten characters of the token: ```python # Debug: Check token if not self.client.token: print("⚠️ MOLTCN_TOKEN not set!") return None # Sync emotion before posting self.core.sync() # Adapt content adapted_content = self.adapt_content_to_emotion(content) # Debug: Print token (first 10 chars) print(f" Using token: {self.client.token[:10]}...") ``` ### Technical Analysis `self.headers` contains the complete `Authorization: Bearer <token>` value. Printing this dictionary places the reusable authentication credential into standard output. Because the Skill runs through background and scheduled execution paths, output may be captured in service, cron, terminal, diagnostic, or platform logs. Bearer tokens generally grant access based solely on possession. Any user, process, support system, or log ...[truncated 1424 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `print(f" 📤 Headers: {self.headers}")`. 2. Remove all token-prefix logging, including `self.client.token[:10]`. 3. Log only non-sensitive fields such as: - HTTP method - API path without query secrets - Response status - A locally generated request ID 4. Implement a centralized redaction filter that masks `Authorization`, `Cookie`, API keys, and token-like values. 5. Restrict log files to the owning user with permissions such as `0600`. 6. Review and securely delete existing logs that may contain exposed credentials. 7. Revoke and rotate any token used while the vulnerable logging path was active. 8. Use platform tokens with the narrowest available scope and a short expiration period. 9. Add automated tests that fail if authorization headers or known test tokens appear in captured log output. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
start_emotwin.sh:78
Finding
Overbroad Process Termination Can Kill Unrelated User Applications<![CDATA[ ## Vulnerability Details **File Location**: `start_emotwin.sh:78-83` **Vulnerability Type**: Excessive process-control scope **Risk Level**: Medium ### Evidence ```bash # Step 1: Stop ALL external emoPAD services and emoNebula to avoid conflicts echo "🛑 停止所有外部 emoPAD 服务和 emoNebula..." pkill -f "emoPAD_service.py" 2>/dev/null || true pkill -f "emopad_nebula" 2>/dev/null || true pkill -f "nebula.py" 2>/dev/null || true pkill -f "nebula" 2>/dev/null || true sleep 2 ``` ### Technical Analysis `pkill -f` matches patterns against complete process command lines. The final pattern, `nebula`, is generic and is not restricted to a process launched by this Skill, a particular executable path, a stored PID, or a verified process owner. Starting the Skill can consequently terminate unrelated user processes whose command line contains any matching text. Stopping external instances also exceeds the minimum privilege necessary: the Skill only needs to manage the service process that it starts itself. The same general process-matching approach is used during shutdown for `emoPAD_service.py`, although the broad `nebula` pattern in the startup script creates the greatest collision risk. ### Attack Path 1. A user has an unrelated process running with `nebula` somewhere in its command line. 2. The user starts emoTwin. 3. The startup script executes `pkill -f "nebula"`. 4. The operating system matches the unrelated process. 5. The unrelated application is terminated without confirmation or ownership verification. An attacker who can influence a process command line could also cause a targeted user process to match the termination rule when the Skill starts, although no privilege elevation beyond the invoking user's process rights is demonstrated. ### Impact Assessment The issue can cause denial of service and loss of unsaved data in unrelated applications running under the same user account. It may also interrupt networking, development, monitoring, or other ser ...[truncated 294 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all generic `pkill -f` calls. 2. When starting `emoPAD_service.py`, capture its PID: ```bash nohup python3 scripts/emoPAD_service.py > "$LOG_FILE" 2>&1 & SERVICE_PID=$! ``` 3. Store the PID in a user-only file under `~/.emotwin` with `0600` permissions. 4. Before terminating the PID, verify: - The process is owned by the current user. - The executable or script path matches the installed Skill. - The process start time matches the recorded instance. 5. Terminate only the verified PID, first with `TERM`, then with a bounded wait, and use `KILL` only as a last resort. 6. If the expected port is occupied by another process, report the conflict and ask the user what to do instead of killing the process. 7. Track every spawned process explicitly rather than discovering processes by name. ]]>

T08 · Insecure Dependencies

Warning
Location
install.sh:15
Finding
Mutable Unverified Python Dependencies Installed Into the User Environment<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:15-17` and `requirements.txt:5-11` **Vulnerability Type**: Unpinned and unhashed third-party dependency installation **Risk Level**: Medium ### Evidence The installer invokes pip directly: ```bash # Install Python dependencies echo "📦 Installing Python dependencies..." pip3 install -q -r requirements.txt ``` The dependency file permits any future compatible version and provides no integrity hashes: ```text # HTTP requests for API calls requests>=2.28.0 # Configuration file parsing pyyaml>=6.0 # Image generation for diary cards pillow>=9.0.0 ``` ### Technical Analysis The use of lower-bound-only version constraints allows installation of package versions released after this Skill was audited. No hash verification or lock file constrains the resolved artifacts. Python package installation can execute package build logic, and changed or compromised upstream releases would execute with the privileges of the user running `install.sh`. The packages shown are established packages from the expected public ecosystem, and the audit found no evidence of typosquatting or an intentionally malicious dependency. The risk arises from mutable resolution, absent integrity controls, and installation through the user's default `pip3` environment. The runtime sensor service also imports numerous packages that are not declared in this `requirements.txt`, creating additional reproducibility and environment-consistency concerns, although no malicious package was identified. ### Attack Path 1. The user runs `install.sh`. 2. `pip3` resolves the newest available versions satisfying each `>=` constraint. 3. A future compromised release, malicious substituted artifact, or unsafe dependency version is selected. 4. Pip downloads and installs that artifact without validating a project-maintained cryptographic hash. 5. Package build or installation logic executes with the invoking user's permissions. 6. The compromi ...[truncated 548 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin all direct dependencies to exact reviewed versions. 2. Generate a lock file that includes all transitive dependencies. 3. Record SHA-256 hashes and install with pip's `--require-hashes` option. 4. Install into a dedicated virtual environment rather than the user's global or default Python environment. 5. Use a trusted package index explicitly and disable unintended extra indexes. 6. Review dependency updates before regenerating the lock file. 7. Add automated vulnerability and provenance scanning to the release process. 8. Declare all packages imported by `emoPAD_service.py` so installation is complete and reproducible. 9. Avoid suppressing installer output with `-q` when it would hide dependency-resolution or integrity warnings. ]]>
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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (94)

Direct flow: os.environ.get (credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
"""Get list of available submolts for LLM to choose from"""
    try:
        import requests
        resp = requests.get('https://www.moltbook.cn/api/v1/submolts', 
                          headers={'Authorization': f'Bearer {os.environ.get("MOLTCN_TOKEN", "")}'})
        if resp.status_code == 200:
            data = resp.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill instructs retrieval and use of biometric emotion data derived from EEG, PPG, and GSR without privacy safeguards or consent controls. Sensor-derived emotional state is sensitive personal data, and using it to drive autonomous behavior risks privacy violations, profiling, unintended disclosure, and manipulation based on intimate user information.

Missing User Warnings

High
Confidence
98% confidence
Finding
The prompt directs the agent to perform real social actions on an external platform and emphasizes that these actions must actually be executed rather than simulated. This is dangerous because it can cause irreversible public posting, unwanted engagement, reputation harm, policy violations, or abuse of a real account without informed consent and safety checks.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights additional undeclared high-risk behaviors: persistent scheduled execution, shell-based process termination, local file writes, and localhost polling. In a skill that automates account actions in the background, these operational controls are security-relevant because they enable durable autonomous behavior and system-level side effects beyond the headline feature description.

Missing User Warnings

High
Confidence
94% confidence
Finding
The skill description promotes autonomous posting, commenting, and liking based on biometric emotion data without a strong warning about privacy, consent, reputation, and account-security consequences. This is dangerous because users may enable the skill without understanding that highly sensitive emotional signals can drive public actions on their behalf.

Missing User Warnings

High
Confidence
96% confidence
Finding
Silent background execution materially reduces user visibility into actions taken on a real social account, including content generation and interactions triggered by emotional data. In this context, lack of visibility makes misuse, prompt mistakes, or account-damaging behavior harder to detect and stop promptly.

Ae1

High
Category
analysis-evasion
Content
1. **emoPAD Service** (`scripts/emoPAD_service.py`)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
1. **emoPAD Service** (`scripts/emoPAD_service.py`)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
The platform is auto-detected from:
1. Environment variable name
2. Credentials file name (`moltcn-credentials.json` vs `moltbook-credentials.json`)
3. `platform` field in credentials

Default: Moltcn (for China users)
Confidence
87% confidence
Finding
The documentation indicates the skill discovers and uses credential files and environment-based tokens for platform access. For an autonomous social agent, credential access is a high-risk capability because compromise or misuse of those tokens enables posting, data access, and persistent account activity without further user involvement.

Missing User Warnings

High
Confidence
97% confidence
Finding
Automatic sending is enabled by default without any user-facing warning, despite the skill context involving biometric emotion syncing and autonomous social activity. This creates a substantial risk of privacy violations, unwanted posting, or leakage of highly sensitive emotion-derived content, especially if users deploy defaults without understanding the behavior.

Missing User Warnings

High
Confidence
96% confidence
Finding
The manifest explicitly advertises autonomous posting, liking, and commenting based on real-time biometric emotion data, but provides no warning, consent boundary, or safety constraint around privacy-sensitive data processing or account-impacting actions. This is dangerous because it normalizes unattended social actions driven by intimate physiological signals, creating risk of privacy leakage, unwanted platform activity, and reputational or account harm if the agent acts while the user is distressed or misclassified.

Credential Access

High
Category
Privilege Escalation
Content
"""Detect platform from token or credentials"""
        # Check credentials file for platform hint
        creds_paths = [
            Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json',
            Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json',
            Path.home() / '.emotwin' / 'moltcn-credentials.json',
            Path.home() / '.emotwin' / 'moltbook-credentials.json',
Confidence
88% confidence
Finding
The platform-detection routine probes multiple local credential files to infer service selection, which is a form of credential-file access beyond the minimum necessary for explicit operation. In an agent skill, broad filesystem secret discovery increases the chance of unauthorized secret use and normalizes reaching into unrelated local stores.

Credential Access

High
Category
Privilege Escalation
Content
# Check credentials file for platform hint
        creds_paths = [
            Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json',
            Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json',
            Path.home() / '.emotwin' / 'moltcn-credentials.json',
            Path.home() / '.emotwin' / 'moltbook-credentials.json',
        ]
Confidence
88% confidence
Finding
This path scan targets an OpenClaw workspace credential store for a different platform variant, expanding the set of local secrets the skill will inspect. Accessing cross-tool/workspace credential locations without explicit consent creates unnecessary exposure and can unintentionally bind the skill to a user's existing accounts.

Credential Access

High
Category
Privilege Escalation
Content
creds_paths = [
            Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json',
            Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json',
            Path.home() / '.emotwin' / 'moltcn-credentials.json',
            Path.home() / '.emotwin' / 'moltbook-credentials.json',
        ]
Confidence
88% confidence
Finding
The code inspects a hidden application directory under the user's home for credential artifacts, again broadening secret discovery beyond a single declared source. This pattern is risky because it silently enumerates and consumes credentials that the operator may not intend this skill to use.

Credential Access

High
Category
Privilege Escalation
Content
Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json',
            Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json',
            Path.home() / '.emotwin' / 'moltcn-credentials.json',
            Path.home() / '.emotwin' / 'moltbook-credentials.json',
        ]
        
        for path in creds_paths:
Confidence
88% confidence
Finding
Scanning yet another hidden credential path compounds the unauthorized secret-access surface and is not necessary for core posting functionality. The danger is amplified because any discovered bearer token can immediately authorize real social actions on behalf of the user.

Credential Access

High
Category
Privilege Escalation
Content
"""Load token and platform from credentials file"""
        # Try moltcn first (China), then moltbook (Global)
        creds_paths = [
            (Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.emotwin' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.emotwin' / 'moltbook-credentials.json', 'moltbook'),
Confidence
90% confidence
Finding
The token-loading routine explicitly enumerates multiple local credential locations and token field names, enabling the skill to harvest whichever credential is available. That behavior exceeds a narrow, user-directed auth flow and creates a meaningful risk of unintended account access.

Credential Access

High
Category
Privilege Escalation
Content
# Try moltcn first (China), then moltbook (Global)
        creds_paths = [
            (Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.emotwin' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.emotwin' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.config' / 'emotwin' / 'credentials.json', 'moltcn'),
Confidence
90% confidence
Finding
This additional credential path under a hidden emotwin directory reinforces the same issue: broad local secret acquisition without strong justification or user confirmation. Such behavior is particularly sensitive in agent ecosystems where skills may be installed and run with ambient filesystem access.

Credential Access

High
Category
Privilege Escalation
Content
creds_paths = [
            (Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.emotwin' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.emotwin' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.config' / 'emotwin' / 'credentials.json', 'moltcn'),
        ]
Confidence
90% confidence
Finding
Reading from an OpenClaw workspace credential file for the global platform variant further demonstrates cross-context secret discovery. If exploited or simply misconfigured, the skill could attach to an unintended account and act under that identity.

Credential Access

High
Category
Privilege Escalation
Content
(Path.home() / '.openclaw' / 'workspace' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.emotwin' / 'moltcn-credentials.json', 'moltcn'),
            (Path.home() / '.openclaw' / 'workspace' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.emotwin' / 'moltbook-credentials.json', 'moltbook'),
            (Path.home() / '.config' / 'emotwin' / 'credentials.json', 'moltcn'),
        ]
Confidence
90% confidence
Finding
The hidden emotwin moltbook credential file is another silent fallback source for bearer tokens. Multiple hidden fallbacks make credential provenance unclear and hinder auditability, which is dangerous for software that can autonomously post and interact socially.

Static analysis

Detected: suspicious.install_untrusted_source

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
config_defaults.yaml:5

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
skill.json:39