T08 · Insecure Dependencies
- Location
README.md:10- Finding
Unpinned Installation from Mutable Remote Sources
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to be a legitimate Pexo video wrapper, but its shell setup handles API credentials in ways that create review-worthy security risk.
Install only if you trust Pexo and are comfortable sending prompts, business details, and uploaded media to its hosted service. Use a narrowly scoped Pexo API key, store ~/.pexo/config with 600 permissions, avoid setting PEXO_BASE_URL away from https://pexo.ai unless you fully trust the endpoint, and inspect the exact installed commit rather than relying on an unpinned install command.
README.md:10Unpinned Installation from Mutable Remote Sources
scripts/_common.sh:6Configuration File Is Executed as Arbitrary Shell Code
scripts/_common.sh:228Bearer API Key and User Data Can Be Sent to an Unrestricted Configurable Endpoint
references/SETUP-CHECKLIST.md:8Plaintext API-Key File Is Created Without Restrictive Permissions
scripts/pexo-upload.sh:70Upload Filename Is Embedded into JSON Without Encoding
The declared description is for a high-level founder video creation workflow: taking narrative/site input and producing a completed publish-ready video. The supplied code does not implement script generation, shot generation, model selection, music selection, or video assembly. Instead, it performs a backend utility function for asset retrieval and downloading within Pexo. This is a materially different primary purpose and exposes undeclared capability to access and locally download project assets. While asset handling could be a supporting component of a larger video system, this code chunk by itself does not match the declared user-facing founder-video creation behavior.
The description promises a high-level founder-video generation workflow: provide story/product/pitch/site and Pexo writes the script, generates shots, picks models, and returns a finished video. The code shown does not implement that primary behavior. Instead, it is a low-level project chat submission utility for an already existing Pexo project. It validates message formatting for asset references, constructs a JSON request to /api/chat, waits for server acknowledgement, and returns submission metadata. This is materially narrower and operationally different from the declared end-user purpose, so the description does not accurately represent the supplied code chunk.
The declared description promises a founder-video creation workflow, but the code does not generate scripts, videos, shots, models, or music, and it accepts no founder-story/product input. Its primary purpose is instead operational diagnostics for a shell-based Pexo setup. While contacting Pexo services is related to the same vendor, the concrete behavior is materially different: setup validation and auth checking rather than media creation. The code also accesses local configuration files and validates API credentials, capabilities that are not reflected in the description.
The declared description says this skill creates founder videos end-to-end. The supplied code does not generate scripts, shots, models, music, or any video asset. Its sole purpose is to query the authenticated user's entitlements and available credits, then optionally suggest purchasing more credits. That is a materially different primary purpose and involves access to account/plan data not disclosed by the description. Therefore the description does not accurately represent the code's behavior.
The declared description presents a high-level content-generation skill that produces a complete founder video from user input. The supplied code chunk does not perform any of those functions. It only creates a new Pexo project by sending a project_name to /api/biz/projects and returning the projectId. This is a materially different primary purpose from founder video creation, and the code lacks any logic for ingesting story/product/site content or generating scripts, visuals, models, music, or a final video. Therefore the description does not accurately represent the behavior of this code chunk.
The description promises end-user creative generation of founder videos. The code chunk instead implements a backend status-inspection helper for an existing Pexo project. Its primary function is to read project metadata and message history, infer whether an agent should wait/respond/deliver/reconnect, and output normalized JSON. While this may support a larger founder-video workflow, the actual behavior in this chunk is not accurately represented by the declared description and introduces undeclared capabilities around project/history access and orchestration.
The declared description promises a content-generation workflow for producing founder videos from user-provided story or website input. The actual code does not create scripts, generate shots, pick models, compose music, or render videos. Instead, it performs a paginated API read to list projects for the authenticated user. This is a materially different primary purpose and an undeclared capability, so the description does not accurately represent the code.
The declared description promises an end-to-end founder video creation capability: taking narrative or website input and producing a completed founder video with music. The actual code does something much narrower and materially different: it uploads an existing local media file into a Pexo project via an upload-credential/upload/finalize flow. While asset upload could be a supporting part of a broader video pipeline, this code chunk by itself only provides generic media ingestion and lacks any logic for script generation, shot planning, model selection, music addition, or final video rendering. Therefore the code does not accurately represent the declared primary purpose.
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 README explicitly states that user-provided story, pitch, or pasted website content is sent to a hosted backend where scriptwriting, model selection, prompts, music, and subtitles happen server-side, yet it gives no clear privacy, retention, or transmission warning. Users may unknowingly transmit sensitive business, personal-brand, fundraising, or proprietary product information to a third-party service using an API key, creating a meaningful confidentiality and compliance risk.
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 requires shell-capable runtime components (curl, jq, file) and instructs execution of multiple shell scripts, but it does not declare any tool scope restrictions such as permissions or allowed-tools. That creates an avoidable trust gap: a host may grant broader execution capability than users expect, increasing the blast radius if the scripts are modified, compromised, or behave unexpectedly.
The skill instructs persistent reuse of a project_id, relays user requests verbatim to a hosted backend, and continues polling/reconnecting over time. That creates session-persistence and cross-turn data-retention risk: sensitive user content, revisions, and uploaded assets remain tied to a long-lived remote project, which can expose more history than necessary if projects are reused, mishandled, or later accessed by the wrong party.
story or pitch to the hosted Pexo agent and deliver the result; Pexo writes the script, generates
the shots, and assembles a personal, polished 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
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.
mkdir -p ~/.pexo
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.
- `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:
This code reads the sensitive PEXO_API_KEY and formats it into a Bearer Authorization header for outbound requests. While the behavior is core to the helper's purpose, this file itself provides no user-facing disclosure beyond internal comments, and the rule specifically calls for warning when sensitive credentials are accessed or transmitted unless documented elsewhere.
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 \
The script executes source "$config_path" on a path influenced by PEXO_CONFIG or defaulting to a user-writable file. That means any shell code placed in the config file will run with the privileges of whoever launches the diagnostic script, turning a configuration read into arbitrary code execution.
Beyond the code-execution issue itself, the script gives no explicit warning that opening the config file will execute shell code. Users are encouraged to create ~/.pexo/config as if it were inert data, which increases the chance they or another tool place unsafe content there and unknowingly trigger command execution.
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>"'
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; }
No suspicious patterns detected.