Back to skill

Security audit

zola-api

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent, but it gives broad direct access to live Zola account data, including write and delete operations, using a long-lived session credential.

Install only if you are comfortable giving the agent direct, token-based access to your Zola account and live wedding data. Treat the refresh token like a password, avoid pasting raw errors or tokens into chats or logs, and manually review any POST, PUT, or DELETE command before running it.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (42)

Credential Access

High
Category
Privilege Escalation
Content
signed-in `zola.com` session. Same credential `zola-mcp` uses:

```sh
# Prefer the env var zola-mcp itself reads (check its .env first):
grep -h ZOLA_REFRESH_TOKEN ~/git/zola-mcp/.env 2>/dev/null
export ZOLA_REFRESH_TOKEN='eyJhbGciOi...'   # or export directly if you have it
```
Confidence
97% confidence
Finding
The skill explicitly instructs the user to retrieve a long-lived refresh token from a local .env file and export it into the shell, which is a direct credential-access pattern. In this agent-skill context, that is dangerous because it normalizes secret extraction from local files and places a powerful account credential into process environment and shell history, increasing risk of theft, misuse, and account compromise.

Credential Access

High
Category
Privilege Escalation
Content
```sh
# Prefer the env var zola-mcp itself reads (check its .env first):
grep -h ZOLA_REFRESH_TOKEN ~/git/zola-mcp/.env 2>/dev/null
export ZOLA_REFRESH_TOKEN='eyJhbGciOi...'   # or export directly if you have it
```
Confidence
96% confidence
Finding
The example shows exporting a bearer-like refresh token directly in the shell, which can leak through shell history, process inspection, logs, crash reports, or downstream command invocation. Because the token is described as long-lived and enables minting session tokens, exposure could grant sustained unauthorized access to sensitive wedding, guest, and registry data as well as write capabilities.

Ae1

High
Category
analysis-evasion
Content
`references/mobile-api-endpoints.md` reuses `$BASE`, `$SESSION_TOKEN`,
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
`references/mobile-api-endpoints.md` reuses `$BASE`, `$SESSION_TOKEN`,
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
98% confidence
Finding
The file provides add, bulk update, and delete guest-group commands, and even notes a wipe risk for `event_invitations`, but it does not frame these operations with an explicit user-facing warning about data loss or accidental modification of guest records. Because these operations affect invitation and address data for real guests, the missing warning is safety-relevant.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
All four follow the same list/add/update/remove shape;
`{wedding_account_id: $ACCT}` and an `_entity_id: 0` (create) or the real id
(update) prefix every write body. Deletes share one path shape:
`DELETE /v3/websites/{pages}/{entities}/{entity_id}/wedding-accounts/$ACCT`
where `{pages}` is looked up per-type from
`GET /v3/websites/pages/wedding-accounts/full` (`.data.{home,faq,poi,travel}_page.page_id`).
Confidence
80% confidence
Finding
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).

Vague Triggers

Medium
Confidence
95% confidence
Finding
The manifest description says the skill triggers on specific phrases or "any Zola wedding data request that should hit the API directly." That final condition is overly broad and lacks clear boundaries or exclusion cases, making unintended invocation more likely for ordinary Zola-related requests.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill instructs users to perform direct authenticated API access and account mutations using long-lived tokens, but it lacks an upfront warning about privacy, credential sensitivity, and the possibility of changing or destroying wedding data. In this context, omission of such warnings materially increases the chance of unsafe use, accidental writes, and disclosure of sensitive personal information.

External Transmission

Medium
Category
Data Exfiltration
Content
UA='Zola/42.5.0 (iPad; iOS 26.4; Scale/2.0)'

# 1. Mint a 30-min session token from the refresh token
SESSION_TOKEN=$(curl -sS -X POST "$BASE/v3/sessions/refresh" \
  -H 'content-type: application/json' -H 'accept: application/json' \
  -H "x-zola-platform-type: iphone_app" -H "x-zola-session-id: $DEVICE_SESSION_ID" \
  -H "user-agent: $UA" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**List booked vendors** — `POST /v3/account-vendors/booked-list` body `{}`:

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/account-vendors/booked-list" -d '{}' \
  | jq '.data.booked_vendors'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Search vendors (typeahead)** — `POST /v3/reference-vendors/typeahead-taxonomy`:

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/reference-vendors/typeahead-taxonomy" \
  -d '{"query":"Acme Photography","taxonomy_key":"wedding-photographers"}' | jq '.data'
# taxonomy_key default: wedding-venues. Other keys: wedding-planners, wedding-bands-djs, ...
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This markdown file includes direct instructions for booking, updating, and unbooking vendors against production endpoints, but it does not include any caution, confirmation guidance, or warning that these actions change live user data. Similar write patterns recur throughout the document, so users may execute irreversible or impactful operations without clear disclosure in the skill description.

External Transmission

Medium
Category
Data Exfiltration
Content
`vendor_type`, then `PUT /v5/account-vendors/vendor` (note: **v5**, not v3):

```sh
curl -sS "${HJ[@]}" -X PUT "$BASE/v5/account-vendors/vendor" -d '{
  "uuid": "<slot-uuid-from-booked-list>", "id": 0, "vendor_type": "PHOTOGRAPHER",
  "booked": true, "booking_source": "BOOKED_VENDORS",
  "price_cents": 350000, "event_date": null,
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Unbook a vendor** — `POST /v3/account-vendors/vendor/unbook`:

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/account-vendors/vendor/unbook" \
  -d '{"uuid":"<vendor-uuid>"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
rejects a bare partial):

```sh
curl -sS "${HJ[@]}" -X PUT "$BASE/v3/budgets/items" -d '{
  "item_uuid": "<uuid>", "taxonomy_node_uuid": "<from-get>",
  "estimated_cost_cents": <from-get>, "actual_cost_cents": 250000,
  "note": "Deposit paid", "item_type": "<from-get, e.g. VENUE>",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
guest object, no `{guest:{...}}` wrapper):

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/guestlists/directory/wedding-accounts/$ACCT" \
  -d '{"sort_by_name_asc": true}' \
  | jq '.data.guest_groups[] | {guest_group_id, guests: [.guests[] | {guest_id, first_name, family_name, rsvp}]}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Add a guest group** — `POST /v3/guestlists/groups`:

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/guestlists/groups" -d '{
  "wedding_account_id": '"$ACCT"',
  "guests": [{
    "first_name": "Mike", "family_name": "Smith", "relationship_type": "PRIMARY",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```sh
# 1. GET the directory (above), find the target group by guest_group_id,
#    keep its `guests[]` array as-is except the address fields you're changing.
curl -sS "${HJ[@]}" -X PUT "$BASE/v3/guestlists/groups/wedding-accounts/$ACCT/bulk/directory" \
  -d '{"updated_guest_groups": [ <full-group-object-with-patched-guest-addresses> ]}' \
  | jq '.data'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Remove a guest group** — `PUT /v3/guestlists/groups/wedding-accounts/$ACCT/delete`:

```sh
curl -sS "${HJ[@]}" -X PUT "$BASE/v3/guestlists/groups/wedding-accounts/$ACCT/delete" \
  -d '{"wedding_account_id": '"$ACCT"', "guest_group_ids": [<id>]}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Assign a seat** — `PUT /v3/seating-charts/seats`:

```sh
curl -sS "${HJ[@]}" -X PUT "$BASE/v3/seating-charts/seats" -d '{
  "guest_uuid": "<guest-uuid>", "seat_uuid": "<seat-uuid>",
  "table_uuid": "<table-uuid>", "seating_chart_uuid": "<chart-uuid>"
}' | jq '.'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
## Inquiries (`src/tools/inquiries.ts`)

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/inquiries/unified-inquiries" -d '{}' \
  | jq '.data[].inquiry_summaries[] | {inquiry_uuid, vendor_name: .vendor_card.vendor_name, unread, status_text}'

curl -sS "${H[@]}" "$BASE/v3/inquiries/<inquiry-uuid>/conversation" | jq '.data.messages'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
from the GET):

```sh
curl -sS "${HJ[@]}" -X PUT "$BASE/v3/websites/events/<event_id>" -d '{
  "event_entity_id": <event_id>, "uuid": "<from-get>", "wedding_account_id": '"$ACCT"',
  "type": "<from-get>", "name": "Reception", "start_at": "<from-get>", "end_at": "<from-get>",
  "timezone": "<from-get>", "venue_name": "The Grand Hall", "address1": "", "address2": "",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```sh
curl -sS "${H[@]}" "$BASE/v4/your-wedding" | jq '.data'

curl -sS "${HJ[@]}" -X POST "$BASE/v3/storefronts/search" -d '{
  "taxonomy_node_id": 2, "city": "Charlotte", "state": "NC",
  "limit": 24, "offset": 0, "facets": {},
  "metro_types": ["HOME","HOME_SERVICE","AWAY"], "metros": [],
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
## Registry items (`src/tools/registry-items.ts`)

```sh
curl -sS "${HJ[@]}" -X POST "$BASE/v3/categories/<category_id>/entities" \
  -d '{"offset":0,"limit":50,"registry_id":"'"$REG"'"}' | jq '.data'

# Default collection id: `.data.default_collection_id` from the registry GET
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# Default collection id: `.data.default_collection_id` from the registry GET
# above, or the first `groups[].modules[]` entry with `type == "COLLECTION"`.
curl -sS "${HJ[@]}" -X POST "$BASE/v3/registries/$REG/collections/<collection_id>" \
  -d '{"sku_id":"<sku>","quantity":1,"most_wanted":false,"enable_group_gifting":false}' \
  | jq '.data'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.