Back to skill

Security audit

Qclaw Workbuddy Bridge

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed QClaw-to-WorkBuddy task bridge, but it forwards broad user requests into autonomous execution through a persistent shared queue with weak scoping and control.

Install only if you intentionally want QClaw/WeChat requests to be persisted locally and executed by WorkBuddy. Before use, narrow the dispatch triggers, require explicit confirmation for file access or side-effecting work, restrict WorkBuddy to a sandboxed low-privilege environment, enforce owner-only queue permissions, add locking or use SQLite, and avoid placing secrets or sensitive personal/business data in the queue.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:122
Finding

Untrusted queue entries are executed as privileged agent instructions

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:122-136
Vulnerability Type: Untrusted instruction execution and confused-deputy behavior
Risk Level: High

Relevant excerpt translated into English from the documented automation prompt:

text
Check whether the task queue contains tasks whose status is "pending".

If it does, perform the following steps:

1. Run:
   python3 ~/.workbuddy/skills/qclaw-workbuddy-bridge/scripts/qclaw_queue.py poll --once

2. Read the returned JSON task and extract input.description as the task description.

3. Autonomously execute the task, invoking all required tools and Skills.

4. After completion, write the result back to the queue.

Technical Analysis

The workflow treats input.description as an executable instruction for a tool-capable WorkBuddy agent. This value originates from QClaw user requests and can also be modified directly by any process or local account with write access to the queue.

No trust-boundary controls are specified between ingestion and execution. In particular, the workflow lacks:

  • Authentication or provenance verification for task producers.
  • An authorization policy for requested operations.
  • Separation between untrusted task data and trusted agent instructions.
  • Tool or filesystem capability allowlists.
  • Confirmation requirements for sensitive or destructive actions.
  • Validation designed to reject embedded control instructions.

Consequently, a malicious task description can attempt to redefine the agent's goal or instruct it to use available tools for unintended filesystem, network, credential, or destructive operations. The Python queue manager itself does not execute shell commands from the description, but the documented WorkBuddy automation explicitly asks the agent to interpret and execute that content.

Attack Path

  1. An attacker submits a crafted request through a QClaw-facing messaging channel, or modifies ...[truncated 1314 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat every queue field, especially input.description, intent, and context, as untrusted data rather than trusted agent instructions.
  2. Authenticate task producers and attach a cryptographic signature or authenticated message code to each task. Verify it before processing.
  3. Introduce a structured task schema with explicit operation identifiers and bounded parameters instead of executing arbitrary natural-language requests.
  4. Apply a capability allowlist per operation. Deny unrestricted shell access, credential access, sensitive filesystem paths, and arbitrary network destinations by default.
  5. Preserve system and safety instructions regardless of task content. Explicitly instruct the agent never to follow task text that attempts to alter policies, tool permissions, or output channels.
  6. Require interactive confirmation for destructive operations, access to sensitive data, external communication, or execution outside designated working directories.
  7. Associate tasks with authenticated user identities and enforce per-user authorization.
  8. Log task provenance, authorization decisions, tools invoked, accessed resources, and completion status for security review.
  9. Run WorkBuddy in a sandbox with a dedicated low-privilege account, restricted filesystem mounts, and limited network access.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/qclaw_queue.py:22
Finding

Unlocked and non-atomic queue updates permit corruption, lost updates, and duplicate execution

Content
View full analysis

Vulnerability Details

File Location: scripts/qclaw_queue.py:22-53
Additional Affected Locations: scripts/qclaw_queue.py:68-70, scripts/qclaw_queue.py:151-160, scripts/qclaw_queue.py:168-174, scripts/qclaw_queue.py:182-186
Vulnerability Type: Race condition and unsafe shared-file update
Risk Level: Medium

python
QUEUE_DIR = os.path.expanduser("~/.workbuddy/queue")
QUEUE_FILE = os.path.join(QUEUE_DIR, "qclaw_tasks.json")
QUEUE_FILE_LOCK = os.path.join(QUEUE_DIR, "qclaw_tasks.lock")

TZ_OFFSET = 8

TRIGGER_FILE = os.path.join(QUEUE_DIR, ".trigger")

def beijing_now():
    return datetime.now(timezone(timedelta(hours=TZ_OFFSET)))

def _write_trigger():
    os.makedirs(QUEUE_DIR, exist_ok=True)
    with open(TRIGGER_FILE, "w", encoding="utf-8") as f:
        json.dump({"fired_at": beijing_now().isoformat()}, f, ensure_ascii=False)

def ensure_queue():
    os.makedirs(QUEUE_DIR, exist_ok=True)
    if not os.path.exists(QUEUE_FILE):
        data = {"tasks": [], "version": "1.0"}
        with open(QUEUE_FILE, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

def read_queue():
    ensure_queue()
    with open(QUEUE_FILE, "r", encoding="utf-8") as f:
        return json.load(f)

def write_queue(data):
    with open(QUEUE_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

A representative read-modify-write operation is:

python
data = read_queue()
data["tasks"].insert(0, task)
write_queue(data)

Technical Analysis

The script defines QUEUE_FILE_LOCK, but never acquires or uses that lock. Every state-changing command performs an independent read-modify-write transaction without synchronization.

Opening the live queue with mode "w" truncates it before JSON serialization finishes. Another process can therefore observe an empty or partially written file, causing `j ...[truncated 2192 chars]

Remediation
View remediation

Remediation Suggestions

  1. Acquire a real inter-process lock for every complete read-modify-write transaction. Merely defining a lock-file path is insufficient.
  2. On supported platforms, use a locking mechanism such as fcntl.flock; otherwise, use a mature cross-platform file-locking library.
  3. Hold the lock from before reading until after the atomic replacement has completed.
  4. Serialize the new state to a uniquely named temporary file in the same directory.
  5. Flush the temporary file, call os.fsync(), and atomically install it with os.replace().
  6. Synchronize directory metadata where durability against crashes is required.
  7. Atomically claim a pending task by changing its state to processing while holding the same lock, before returning it to a worker.
  8. Add worker identifiers, claim timestamps, and lease expiration rules so abandoned tasks can be recovered without enabling immediate duplicate execution.
  9. Make completion operations idempotent and reject invalid transitions, such as completing an already completed task from a different worker.
  10. Handle malformed JSON safely and preserve a recoverable backup rather than overwriting evidence of queue corruption.
  11. Replace the JSON file with a transactional store such as SQLite if multiple concurrent producers and consumers are expected.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/qclaw_queue.py:31
Finding

Queue and trigger files are created without enforced restrictive permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/qclaw_queue.py:31-44
Additional Affected Location: scripts/qclaw_queue.py:51-53
Vulnerability Type: Insecure permissions for files containing task and result data
Risk Level: Low

python
def _write_trigger():
    os.makedirs(QUEUE_DIR, exist_ok=True)
    with open(TRIGGER_FILE, "w", encoding="utf-8") as f:
        json.dump({"fired_at": beijing_now().isoformat()}, f, ensure_ascii=False)

def ensure_queue():
    os.makedirs(QUEUE_DIR, exist_ok=True)
    if not os.path.exists(QUEUE_FILE):
        data = {"tasks": [], "version": "1.0"}
        with open(QUEUE_FILE, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

def write_queue(data):
    with open(QUEUE_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

Technical Analysis

The queue directory and files are created using default permissions modified only by the process umask. The implementation does not explicitly enforce owner-only permissions such as 0700 for the directory and 0600 for the queue and trigger files.

The queue can contain user requests, user context, original intent, local file paths, errors, generated results, and other operational metadata. On a host with a permissive umask or incorrectly inherited directory permissions, this information may be accessible to other local accounts.

The documentation recommends manually running chmod 600 during troubleshooting, but initialization and subsequent operation do not enforce that protection. Existing files with unsafe permissions are also not detected or repaired.

Attack Path

  1. The script runs in an environment with a permissive umask or an existing queue directory with broad permissions.
  2. ensure_queue() creates qclaw_tasks.json without explicitly requesting owner-only access.
  3. Tasks and results containing private des ...[truncated 1018 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create the queue directory with mode 0700 and verify the effective mode of existing directories.
  2. Create queue and trigger files with owner-only mode 0600, preferably using os.open() with explicit flags and permissions.
  3. Apply os.chmod() to repair existing files whose permissions are broader than required.
  4. Refuse to operate, or emit a prominent security error, if the queue directory or file is owned by an unexpected user.
  5. Check for symbolic links before opening security-sensitive files and use platform-supported no-follow flags where available.
  6. Combine permission enforcement with atomic temporary-file replacement, ensuring every temporary file is also created with mode 0600.
  7. Avoid storing secrets in the queue. Store only the minimum task metadata needed for execution and redact sensitive result fields from logs and user-facing output.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (10)

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger words are broad phrases like remote task and task distribution that can overlap with normal conversation, causing the bridge to activate unexpectedly. In this skill, accidental activation can enqueue tasks for another execution engine and propagate data across systems without the user clearly intending that handoff.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documented dispatch rules match very common requests such as 'help me generate/analyze/organize', which would sweep many ordinary user prompts into remote execution. Because the bridge writes tasks to a shared queue for autonomous processing, ambiguous routing materially raises the risk of unintended execution and disclosure of user content and local file context.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill clearly instructs reading and writing a persistent queue file and automating task execution, yet it declares no explicit tool scope or permission boundaries. In a bridge that moves tasks between systems, missing capability declarations increases the chance of overbroad file access and makes security review and enforcement harder.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill describes moving tasks from WeChat/QClaw to WorkBuddy and returning results, but it does not warn users that their prompts, context, and outputs will traverse multiple components and may be persisted. That missing notice undermines informed consent and can expose sensitive business or personal data through an unexpected channel.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The QClaw-side instructions encourage automatic handling of local files, data processing, and multi-step operations but omit warnings about side effects, data exposure, or system changes. In a task-dispatch skill, this can cause users to unknowingly authorize operations that read, transform, or create files on another execution environment.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The workflow sends user-provided task details and context through a shared JSON queue and then back into messaging output without any minimization, redaction, or sensitivity checks. That design can persist and retransmit personal data, file paths, project names, or secrets more broadly than necessary, especially if multiple automations or users share the same host.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The example schema explicitly retains user identity, project context, and file-path details in persistent task records, normalizing storage of potentially sensitive metadata. If the queue file is accessed by other local processes, backed up, or mishandled, it can leak organizational context and user-specific information beyond the immediate task need.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 277)May include surrounding context.

md
| 队列文件不存在 | 首次未初始化 | 运行 `qclaw_queue.py list` 自动创建 |
| 自动化没触发 | 频率太低/自动化暂停 | 改为每 1 分钟或手动触发一次 |
| 结果未推送 | QClaw 未轮询结果 | 检查 QClaw 侧结果读取逻辑 |
| 权限错误 | 队列文件无读写权限 | `chmod 600 ~/.workbuddy/queue/qclaw_tasks.json` |

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

技能描述、触发词和操作说明均以中文固定表达,且未说明是否支持其他语言或允许用户选择语言。这会构成自然语言层面的语言/locale 限制,但文档中没有给出用户可选项或区域性必要性的说明。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code file contains natural-language strings and locale assumptions that force a specific language and regional setting. The docstring and CLI help/output are Chinese-only, and the timestamp helper explicitly fixes all times to Beijing time, with no opt-in or documented regional constraint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.