T01 · Skill Instruction Hijacking
- Location
scripts/vexa-transform.mjs:11- Finding
Untrusted Webhook Payload Is Converted into Agent Instructions and an Executable Command
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches Vexa meeting automation, but its optional webhook path can turn external meeting events into agent commands and persistent memory updates with limited validation.
Review this before installing if you plan to use webhooks or automatic reports. The normal CLI flows are coherent for Vexa, but enabling the webhook can let an external event wake the agent, fetch transcripts, write reports, and alter persistent entity memory. Use only trusted webhook endpoints, avoid custom VEXA_BASE_URL values unless you control them, and manually review transcript-derived memory changes.
scripts/vexa-transform.mjs:11Untrusted Webhook Payload Is Converted into Agent Instructions and an Executable Command
scripts/vexa-transform.mjs:57Webhook-Triggered Transcript Processing Can Poison Persistent Agent Memory
scripts/vexa.mjs:103API Keys Can Be Transmitted to Arbitrary or Plaintext Custom Endpoints
scripts/onboard.mjs:155Webhook Validation Reads Global Agent Session Data and Reuses a Privileged Hook Token
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
- `POST /bots` — request bot (`platform`, `native_meeting_id`, optional `language`, `bot_name`; Teams also needs `passcode`)
- `GET /bots/status` — list running bots
- `PUT /bots/{platform}/{native_meeting_id}/config` — update active bot config (e.g., language)
- `DELETE /bots/{platform}/{native_meeting_id}` — stop bot
- `GET /transcripts/{platform}/{native_meeting_id}` — transcript (during or after meeting)
- `POST /transcripts/{platform}/{native_meeting_id}/share` — temporary share URL
- `GET /meetings` — meeting history
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
- `POST /transcripts/{platform}/{native_meeting_id}/share` — temporary share URL
- `GET /meetings` — meeting history
- `PATCH /meetings/{platform}/{native_meeting_id}` — update metadata (`data.name`, `data.participants`, `data.languages`, `data.notes`)
- `DELETE /meetings/{platform}/{native_meeting_id}` — purge transcript + anonymize finalized meeting only
- `PUT /user/webhook` — set user webhook URL
- `GET /voice-agent-config` — get user's voice agent config (incl. custom `ultravox_system_prompt`)
- `PUT /voice-agent-config` — update voice agent config; set `ultravox_system_prompt` to a string to override, or `null` to reset to service default
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
- `POST /transcripts/{platform}/{native_meeting_id}/share` — temporary share URL
- `GET /meetings` — meeting history
- `PATCH /meetings/{platform}/{native_meeting_id}` — update metadata (`data.name`, `data.participants`, `data.languages`, `data.notes`)
- `DELETE /meetings/{platform}/{native_meeting_id}` — purge transcript + anonymize finalized meeting only
- `PUT /user/webhook` — set user webhook URL
- `GET /voice-agent-config` — get user's voice agent config (incl. custom `ultravox_system_prompt`)
- `PUT /voice-agent-config` — update voice agent config; set `ultravox_system_prompt` to a string to override, or `null` to reset to service default
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
## Safety
- Treat `DELETE /meetings/...` as destructive.
- Require explicit user confirmation for exact meeting identity.
- If delete returns `409`, the meeting is not finalized yet.
The skill invokes shell commands, uses environment-based secrets, and talks to external network services, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates an overly broad execution surface where an agent may run commands or access secrets without a clear policy boundary, increasing the chance of unintended command execution or data exposure.
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
**Webhook — proactive setup:** Whenever secrets exist and you're working with Vexa, run `node skills/vexa/scripts/onboard.mjs --check-webhook`. If `webhook_configured` is false, advise adding the vexa mapping (see `references/webhook-setup.md`). For onboarding-only details (webhook requirements, pipeline validation, mock webhook), load `references/onboarding-flow.md`.
**When secrets are missing:** Direct the user to get their key from https://vexa.ai/dashboard/api-keys and set it up themselves. They should either set `VEXA_API_KEY` in their environment or create `skills/vexa/secrets/vexa.env` manually with `VEXA_API_KEY=their_key_here`. Do not ask users to paste API keys in chat.
**Secrets location:** `skills/vexa/secrets/` holds env files and `vexa-state.json`. This dir is gitignored. When publishing the skill to ClawHub, ensure `secrets/` is excluded.
The non-interactive onboarding example hard-codes --language en, and several core command examples also default to English without indicating that this is only an example or that the user should choose their preferred language. Because this skill handles meeting participation and transcripts, forcing a specific language can violate locale-choice expectations unless explicitly optional or justified.
The markdown explains that the system prompt controls the bot's personality and language, but it does not instruct the operator to preserve or confirm the user's preferred language before changing it. This creates a natural-language policy risk because the skill can steer a meeting bot into a different language setting without explicit user choice.
The onboarding command explicitly passes --language en, which forces a specific language setting. The file does not offer the user a language/locale choice or explain why English is required, so this is a natural-language policy violation under the locale-choice rule.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
Optionally, when a meeting finishes, Vexa can POST to your OpenClaw hooks endpoint. The bundled transform processes the webhook and triggers creation of a basic meeting report.
**This setup is entirely optional.** Without it, you can create reports manually with `vexa.mjs report`. The skill never modifies `openclaw.json` automatically — all changes below are done by you.
## Setup (manual)
The script fetches meeting transcripts and includes a plaintext snippet from the first non-empty transcript segment in its JSON output. Meeting transcripts commonly contain sensitive business, personal, or regulated information, so exposing excerpts in routine audit output can leak data to logs, terminals, CI artifacts, or downstream tools that were not intended to handle transcript content.
This script retrieves sensitive meeting data from the Vexa API and persists it as a plaintext markdown report under the current workspace without any consent gate, warning, or minimization controls in this code path. Because transcripts, participant information, URLs, and meeting metadata can contain confidential business or personal data, running the tool in the wrong context can cause unintentional collection and local exposure of sensitive information.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
#!/usr/bin/env node
/**
* Vexa onboarding helper:
* 1) Capture API key and optionally persist it in skills/vexa/secrets/vexa.env (chmod 600)
* 2) Start a bot for a test meeting
* 3) Poll transcript briefly
* 4) Stop bot
The script inspects ~/.openclaw session data and configuration files, including hook mappings and tokens, to determine whether webhooks were configured or received. This is sensitive host-state access unrelated to the minimum needed for meeting onboarding, and it exposes internal application metadata and credentials to the skill, increasing the blast radius if the skill is misused or modified.
The script can read the host application's hook token from ~/.openclaw/openclaw.json and then use it to send an authenticated POST to the local OpenClaw gateway via --send-mock-webhook or the validation flow. Although framed as testing, this crosses the skill boundary and allows the skill to synthesize trusted Vexa webhook events inside the host application, which could trigger downstream ingestion, report generation, or workflow automation based on forged meeting-completed events.
The transform turns an untrusted webhook payload into operational instructions that direct the agent to modify local memory and entity files, which expands behavior beyond narrowly generating a meeting report. In an agentic environment, this creates a prompt-injection and unauthorized state-modification risk because external event data can trigger persistent changes to local knowledge stores without explicit user approval or strong validation.
The transform embeds the full raw webhook payload directly into the agent-visible message, which may expose transcripts, participant identities, meeting metadata, links, or other sensitive content to downstream model context, logs, and operators. Because webhook payloads are untrusted and potentially rich in sensitive data, indiscriminate inclusion increases both privacy exposure and prompt-injection surface.
The bots:config:update command requires a --language value and applies it directly to bot configuration, which can impose a locale/language setting without any documented opt-in from the end user affected by the bot. This matches the policy concern for language or locale constraints being enforced without an explicit user choice.
The manifest focuses on joining meetings and obtaining transcripts, recordings, and reports. Setting a user webhook URL is an account/integration-management feature that goes beyond that described scope and is not an obvious implementation detail of joining meetings.
The user:webhook:set command transmits a webhook URL to the Vexa service, which can affect outbound delivery behavior and may expose integration details. Although the code performs the network call directly, there is no confirmation prompt or user-facing warning here beyond basic usage text.
The manifest describes a skill for sending bots to meetings and retrieving transcripts, recordings, and reports. This file additionally exposes commands to read, set, and reset a global voice-agent system prompt, which is a separate agent-configuration capability not implied by the stated meeting-ingestion purpose.
The file comment states its purpose is to 'create a basic meeting report,' implying the transform itself performs report creation. In reality, the code merely returns a message telling an external agent to run vexa.mjs report, then post-process the output and modify entity files.
This is a natural-language constraint embedded in the skill behavior that forces a specific output format for chat messages. Although operationally motivated, it imposes a fixed communication policy without explicit user opt-in or broader context.
Detected: suspicious.dangerous_exec, suspicious.env_credential_access