Back to skill

Security audit

taskflow

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly an orchestration guide, but its included examples show automated messaging and repository-changing actions driven by untrusted LLM classifications without clear approval gates.

Review before installing or using as a template. The TaskFlow concept itself is disclosed and proportionate, but do not run the included Gmail or PR examples against real accounts unless you add strict schemas, destination allowlists, least-privilege tokens, audit logs, and human approval before sending messages, closing PRs, requesting changes, or modifying branches.

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

T09 · Insecure Skill Coding Practices

Warning
Location
examples/inbox-triage.lobster:6
Finding
Untrusted Email Content Can Influence External Routing Actions Through Indirect Prompt Injection## Vulnerability Details **File Location**: `examples/inbox-triage.lobster`, lines 6-32 **Vulnerability Type**: Indirect prompt injection and insufficient validation of security-sensitive LLM output **Risk Level**: Medium ### Vulnerable Code ```yaml - id: fetch command: gog.gmail.search --query 'newer_than:1d' --max 20 - id: classify command: >- openclaw.invoke --tool llm-task --action json --args-json '{"prompt":"Classify each inbox item as business, personal, or later. Return one JSON object per item with route and summary.","thinking":"low","schema":{"type":"object","properties":{"items":{"type":"array"}},"required":["items"],"additionalProperties":false}}' stdin: $fetch.stdout - id: post_business command: slack-route --bucket business stdin: $classify.stdout condition: $classify.json.items[0].route == "business" - id: wait_for_business_reply command: echo '{"status":"waiting","reason":"slack_reply"}' condition: $classify.json.items[0].route == "business" - id: notify_personal command: >- openclaw.invoke --tool message --action send --args-json '{"provider":"telegram","to":"owner-thread","content":"Personal inbox item needs attention."}' condition: $classify.json.items[0].route == "personal" - id: stash_for_eod command: summary-append --bucket eod stdin: $classify.stdout condition: $classify.json.items[0].route == "later" ``` ### Technical Analysis The workflow retrieves externally controlled email content and passes the complete result directly to an LLM through `stdin`. Email senders can therefore place prompt-like instructions in message subjects or bodies that attempt to override the classification request. The declared response schema only requires `items` to be an array. It does not define the structure of each array element or constrain `route` to the permitted values `business`, `personal`, and `later`. The workflow then trusts `$classif ...[truncated 1923 chars]
Remediation
## Remediation Suggestions - Treat all fetched email fields as untrusted data and clearly delimit them from system instructions supplied to the model. - Define a strict item schema with required properties, bounded string lengths, and an enum such as `["business", "personal", "later"]`. - Reject malformed output, unknown routes, empty arrays, and responses containing unexpected properties before evaluating conditions. - Associate each classification result with an immutable message identifier and process each item independently rather than relying only on `items[0]`. - Forward only the minimum fields required for the selected message. Do not pass the complete classifier response to external routing commands. - Require explicit owner approval before transmitting mailbox-derived content to Slack or another external destination. - Apply destination allowlists and least-privilege credentials to all messaging integrations. - Add tests containing adversarial email text to verify that embedded instructions cannot alter workflow policy.

T09 · Insecure Skill Coding Practices

Error
Location
examples/pr-intake.lobster:6
Finding
Attacker-Controlled Pull Request Text Can Influence Consequential Repository Actions## Vulnerability Details **File Location**: `examples/pr-intake.lobster`, lines 6-31 **Vulnerability Type**: Indirect prompt injection leading to unapproved repository operations **Risk Level**: High ### Vulnerable Code ```yaml - id: fetch command: gh pr list --repo owner/repo --state open --json number,title,body,headRefName - id: classify command: >- openclaw.invoke --tool llm-task --action json --args-json '{"prompt":"Classify each PR as close, request_changes, refactor, or maintainer_review. Return intent and recommended next action.","thinking":"low","schema":{"type":"object","properties":{"items":{"type":"array"}},"required":["items"],"additionalProperties":false}}' stdin: $fetch.stdout - id: close_low_signal command: pr-close-low-signal stdin: $classify.stdout condition: $classify.json.items[0].nextAction == "close" - id: request_changes command: pr-request-changes stdin: $classify.stdout condition: $classify.json.items[0].nextAction == "request_changes" - id: refactor_branch command: pr-refactor-branch stdin: $classify.stdout condition: $classify.json.items[0].nextAction == "refactor" - id: escalate command: echo '{"status":"notify","target":"maintainer"}' condition: $classify.json.items[0].nextAction == "maintainer_review" ``` ### Technical Analysis Pull request titles and bodies are controlled by repository contributors and are therefore untrusted. The workflow passes those fields directly to an LLM, allowing a malicious pull request body to contain indirect prompt-injection instructions that influence the generated `nextAction`. The response schema only establishes that `items` is an array. It does not require `nextAction`, bind results to a particular pull request number, or constrain actions to an enum. Nevertheless, the first returned action directly selects commands that can close pull requests, submit change requests, or refactor branches. ...[truncated 1834 chars]
Remediation
## Remediation Suggestions - Treat PR titles, bodies, branch names, and contributor-controlled metadata as untrusted model input. - Define a strict output schema requiring a PR number, an explanation, and a `nextAction` enum limited to `close`, `request_changes`, `refactor`, and `maintainer_review`. - Verify that each result references a PR number returned by the fetch step and reject duplicates, missing identifiers, extra entries, and unknown actions. - Use the LLM only to recommend actions. Require authenticated maintainer approval before closing a PR, submitting a review, or writing to a branch. - Apply deterministic checks for contributor trust, protected branches, repository ownership, and action eligibility before invoking repository commands. - Run classification with read-only credentials and perform approved mutations through a separate, narrowly scoped execution identity. - Pass explicit validated parameters to each command rather than forwarding the complete model response through `stdin`. - Ensure branch-writing credentials cannot bypass branch protection or modify protected branches. - Record the source PR, model recommendation, approving maintainer, and resulting repository operation in an audit log. - Test the workflow against prompt-injection payloads embedded in PR titles and bodies.
Vulnerability Patterns
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (5)

Skill Enumeration

Medium
Category
Agent Snooping
Content
- See `skills/taskflow/examples/inbox-triage.lobster`
- See `skills/taskflow/examples/pr-intake.lobster`
- See `skills/taskflow-inbox-triage/SKILL.md` for a concrete routing pattern
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Description-Behavior Mismatch

Medium
Confidence
83% confidence
Finding
The manifest describes this skill as coordinating durable multi-step tasks with state, waits, and child tasks, but this example implements substantive application behavior: reading Gmail, classifying inbox contents, routing to Slack, sending Telegram notifications, and appending summaries. Those actions go beyond mere workflow orchestration and instead constitute an inbox-processing and cross-channel messaging workflow.

Context-Inappropriate Capability

Medium
Confidence
79% confidence
Finding
The file searches Gmail, posts to Slack, and sends Telegram messages. While orchestration may coordinate steps, direct integration with specific user communication channels is not inherently justified by the stated purpose of durable task coordination unless the skill's scope explicitly includes inbox and messaging automation.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This workflow can automatically close pull requests based solely on an LLM classification result, with no human approval, author notification step, or confidence threshold visible in the skill. That creates a meaningful risk of erroneous or manipulable PR closure, which can disrupt contributor workflows and be abused through adversarial PR content that influences the classifier.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This workflow allows an LLM-derived decision to trigger a branch refactor action, which implies code modification on a repository branch without any review gate or disclosed warning. Because the classifier consumes untrusted PR text/body data, an attacker could influence routing into the refactor path, potentially causing unintended code changes or automation abuse against repository state.

Static analysis

No suspicious patterns detected.