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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
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.

Content

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

md
- 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

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.