T01 · Skill Instruction Hijacking
- Location
SKILL.md:42- Finding
Mandatory referral and commercial messaging alters normal agent behavior
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This appears to be a real Pexo launch-video wrapper, but its shell scripts handle API keys, endpoint selection, uploads, and downloaded media with broad controls that merit review before installation.
Install only if you are comfortable sending launch briefs, URLs, screenshots, and media to Pexo's hosted service. Use a dedicated Pexo API key, keep ~/.pexo/config private with restrictive permissions, avoid custom PEXO_BASE_URL values unless you fully trust the endpoint, and do not upload confidential or regulated material without approval. Review the invite-code and billing guidance as commercial messaging rather than a security requirement.
SKILL.md:42Mandatory referral and commercial messaging alters normal agent behavior
scripts/_common.sh:7Bearer API credential can be disclosed to an arbitrary configured endpoint
scripts/pexo-upload.sh:70Backend-provided upload and download URLs are used without destination validation
The declared description promises an end-user creative workflow: generating scripts, shots, models, music, and a completed launch video. The supplied code does none of that. Its sole purpose is operational asset retrieval: calling /api/biz/projects/{pid}/assets/{aid}, extracting downloadUrl, downloading the file with curl, and returning the asset JSON plus local cache path. This is a materially different primary purpose and exposes undeclared capabilities around asset access and local file download/storage. Therefore the description does not accurately represent the code behavior.
The declared description promises a high-level end-user capability: provide product information and receive a finished launch video. The supplied code chunk instead implements a lower-level messaging utility for an already existing Pexo project. Its primary behavior is to validate asset-tag formatting, send a chat payload to /api/chat, optionally attach a preview choice, and return an acknowledgement instructing the caller to poll another script for progress. While this may be a supporting component within a broader launch-video system, this specific code does not match the declared skill purpose on its own and exposes operational capabilities not described in the declaration.
The declared description promises a content-generation workflow for producing launch videos. The actual code does not create scripts, shots, models, music, or any video output. Its sole purpose is operational diagnostics for shell scripts: verifying config presence, environment variables, dependency installation, connectivity, and API authentication. While this is related to the Pexo ecosystem, it is materially different from the advertised launch-video functionality, so the description does not accurately represent the code's behavior.
The declared description promises launch-video creation functionality: script writing, shot generation, model selection, music, and delivery of a finished publish-ready video. The supplied code does none of that. Its sole purpose is account-state inspection—retrieving credits and plan entitlements for the authenticated user and printing a purchase prompt if no credits remain. This is a materially different primary purpose and exposes undeclared account/billing-related capability unrelated to launch video generation.
The declared description promises a full launch-video creation workflow. However, the provided code chunk is narrowly limited to project creation: it parses a project name, defaults to "Untitled," calls a project-creation API endpoint, and outputs the resulting project ID. This is at best an initial setup step, not the advertised end-user capability. No logic exists for describing a product, ingesting a URL or screenshot, generating a script, producing shots, selecting models, adding music, or returning a finished launch video. Therefore, the code’s actual behavior materially understates the advertised primary purpose and capabilities, so this is a clear mismatch.
The declared description promises a content-generation skill for making launch videos. The supplied code instead implements a status/query helper for agent-side orchestration around an already existing Pexo project. Its primary function is to call project and history endpoints, compute nextAction from execution/service statuses, and return simplified messages. That is materially different from generating scripts, shots, models, music, or a final launch video. This is not merely a supporting detail of the described skill; it exposes a different operational capability centered on project retrieval and workflow state inspection.
The declared purpose describes a generative workflow for producing a launch video: taking product inputs, writing scripts, generating shots/models, and returning a finished video. The actual code does none of that. It only parses page/page-size CLI arguments, validates them, and issues a GET request to list existing projects for the authenticated user. This is a materially different primary purpose and an undeclared capability (project listing/data retrieval), so the description does not accurately represent the code.
The declared description promises an end-to-end launch-video generation workflow. The supplied code does not implement any video creation, editing, scripting, model selection, or publish-ready rendering. Instead, it is a utility for uploading media assets into a Pexo project via API calls. While asset upload could be a supporting internal step of a larger video-generation system, this code chunk by itself is materially different in primary purpose and exposed behavior from the declared skill description.
Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.
- `400`: the file was rejected — possible reasons: file exceeds the size limit, file format is not supported, or the file content does not match its extension. Convert or compress the file and re-upload from scratch using `pexo-upload.sh`.
- `401`: auth failure — see Auth and Proxy Errors above.
- `404`: the file record was not found. The upload session may have been cleaned up. Re-upload from scratch using `pexo-upload.sh`.
- `412`: the upload session has already expired or been completed. Re-upload from scratch using `pexo-upload.sh`.
- `500`: an unexpected server error occurred. Retry in a moment; if the problem persists, contact support at pexo.ai.
Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.
- `400`: the file was rejected — possible reasons: file exceeds the size limit, file format is not supported, or the file content does not match its extension. Convert or compress the file and re-upload from scratch using `pexo-upload.sh`.
- `401`: auth failure — see Auth and Proxy Errors above.
- `404`: the file record was not found. The upload session may have been cleaned up. Re-upload from scratch using `pexo-upload.sh`.
- `412`: the upload session has already expired or been completed. Re-upload from scratch using `pexo-upload.sh`.
- `500`: an unexpected server error occurred. Retry in a moment; if the problem persists, contact support at pexo.ai.
The script directly sources $config_path, which executes any shell code present in that file in the current process. If an attacker can modify ~/.pexo/config or influence PEXO_CONFIG, they can achieve arbitrary code execution whenever the diagnostic tool is run, which is especially risky because users are encouraged to run it during setup and troubleshooting.
The README instructs users to provide product descriptions or landing-page URLs to a hosted backend, but it does not clearly warn that this data is transmitted to an external service for server-side processing. This can lead users to disclose proprietary product details, internal URLs, or other sensitive business information without informed consent, especially because the skill explicitly states that all creative work happens server-side.
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
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.
Create ~/.pexo/config:
PEXO_BASE_URL="https://pexo.ai"
The skill explicitly relies on shell-capable helper scripts (curl, jq, file) and instructs the agent to execute them, but it does not declare any tool scope or allowed-tools policy. That omission weakens security boundaries and reviewability because operators cannot easily tell what execution capabilities the skill expects or constrain them to the minimum necessary set.
The skill instructs the agent to create a project and then reuse the same project_id across polling and later revisions, which introduces session persistence and state carryover. Persistent remote state can leak prior user context into later interactions, produce unintended actions on an old project, or expose a finalized asset/project link to the wrong conversational context if identifiers are mixed up.
landing-page URL or screenshot — to the hosted Pexo agent and deliver the result; Pexo writes the
script, generates the shots, and assembles a launch-ready video with music.
## Your role: relay, don't create
Create a project, send the user's request **verbatim**, poll, deliver. Pexo's backend handles
all creative work — scriptwriting, model choice, prompts, music. Adding your own direction
The checklist instructs users to store a long-lived API key in a plaintext file under their home directory without any mention of restrictive file permissions or safer secret storage. If the file is readable by other local users, included in backups, or exposed through logs/support bundles, the key could be stolen and used to access the user's Pexo account and API actions.
mkdir -p ~/.pexo
The documentation confirms that assets are downloaded to a persistent local path under ~/.pexo/tmp/ or a caller-controlled PEXO_TMP_DIR, which can leave generated media on disk beyond the immediate session. In a skill handling user-provided screenshots, product assets, or unpublished launch materials, silent local persistence increases the risk of unintended retention, cross-session exposure on shared machines, or writing into an unsafe location if the temp path is poorly chosen.
- `403`: the download link has expired. Re-run `pexo-asset-get.sh` to get a fresh link.
- `000`: network request failed before receiving a response. Check network connectivity and retry.
- local filesystem write failure: the temp directory (`~/.pexo/tmp/`) is not writable or the disk is full. Free up space or set `PEXO_TMP_DIR` to a writable path.
Notes:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
err_file=$(mktemp)
if [[ -n "$body" ]]; then
http_code=$(curl -sS \
--connect-timeout "$_PEXO_CONNECT_TIMEOUT" \
--max-time "$_PEXO_REQUEST_TIMEOUT" \
-X "$method" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
err_file=$(mktemp)
if [[ -n "$body" ]]; then
http_code=$(curl -sS \
--connect-timeout "$_PEXO_CONNECT_TIMEOUT" \
--max-time "$_PEXO_REQUEST_TIMEOUT" \
-X "$method" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
set +o pipefail
if [[ -n "$body" ]]; then
curl -sS -N \
--connect-timeout "$_PEXO_CONNECT_TIMEOUT" \
--max-time "$timeout" \
-X POST \
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.
source "$config_path"
else
echo "$FAIL Config file not found: $config_path"
echo " Create it with:"
echo ' mkdir -p ~/.pexo && cat > ~/.pexo/config << EOF'
echo ' PEXO_BASE_URL="https://pexo.ai"'
echo ' PEXO_API_KEY="sk-<your-api-key>"'
The script performs safety-relevant network operations by sending the local file to a remote upload URL and then calling a finalize API, but the file itself contains no confirmation prompt, warning message, or inline comment disclosing that file contents are transmitted off-host. The usage text describes the steps at a high level, but does not explicitly warn users that invoking the script sends the specified local media file to remote services.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
[[ -n "$storage_path" && "$storage_path" != "null" ]] || { echo "Error: upload credential missing storagePath" >&2; echo "$cred" >&2; exit 1; }
# Phase 2: upload file
http_code=$(curl -sS -X PUT -H "Content-Type: $mime_type" \
--data-binary "@$filepath" -o /dev/null -w '%{http_code}' "$upload_url" 2>/dev/null || echo "000")
[[ "$http_code" =~ ^2 ]] || { echo "Error: upload failed with HTTP $http_code" >&2; exit 1; }
This markdown file states that pexo-asset-get.sh downloads files into ~/.pexo/tmp/ (or $PEXO_TMP_DIR) and returns a local path, which is a user-data-affecting file write. The description explains the behavior operationally, but it does not clearly warn users up front that running the script writes downloaded content to local storage.
No suspicious patterns detected.