Back to skill

Security audit

Selzy Email Marketing

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Selzy marketing helper, but its instructions can send or schedule campaigns before final confirmation and expose API keys or contact data in request URLs.

Review carefully before installing. Use only a restricted Selzy API key if available, never log or share full request URLs, verify list ID, list name, recipient count, sender, subject, body, send time, and timezone, and require a fresh explicit confirmation immediately before every createCampaign call. Enforce the 1-campaign-per-hour limit for campaign creation.

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
SKILL.md:130
Finding

API Credentials and Contact Data Exposed in URL Query Strings

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:463
Finding

Campaign Creation Occurs Before Required User Confirmation

Content
View full analysis
= expected recipients (if count=0, STOP and ask) 3. createEmailMessage → MUST include list_id parameter + confirm subject + content 4. RATE LIMIT CHECK: If created campaign in last 60s, WAIT before proceeding 5. createCampaign → confirm timing + recipient count 6. WAIT for explicit "send" or "confirm" from user ``` ``` A common workflow repeats the same unsafe sequence: ```markdown #### "Create a campaign for my VIP customers" ``` 1. getLists → find VIP list, confirm count (MUST match expected recipients) 2. If count is wrong → STOP and alert user (DO NOT proceed) 3. Ask: subject, content type (promo/newsletter/event) 4. createEmailMessage → MUST include list_id parameter, show preview 5. createCampaign (omit start_time for immediate) 6. ⚠️ WAIT for "send it" or "confirm" before considering it done 7. Report: campaign_id, status, recipient count (verify matches step 1) ``` ``` The Skill separately defines omission of `start_time` as an immediate-send operation: ```markdown | `start_time` | No | Schedule time (YYYY-MM-DD HH:MM:SS). Omit for immediate send | ``` ### Technical Analysis The Skill states that campaigns must never be sent without explicit confirmation, but two operational workflows direct the Agent to call `createCampaign` first and obtain confirmation afterward. This is not merely a cosmetic inconsistency. According to the Skill's own API description, `createCampaign` creates and schedules a campaign, and omitting `start_time` causes an immediate ...[truncated 2218 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (40)

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · README.md (reported line 3)May include surrounding context.

md
# ✉️ Selzy Email Marketing Skill for OpenClaw

Full-featured email marketing skill for managing campaigns via Selzy API. Create campaigns, manage contacts, and analyze results directly from chat.

## 🚀 Quick Start

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README makes a strong security claim that campaigns are never sent without explicit confirmation, yet the documented capabilities include direct send operations and no mechanism in this file demonstrates that confirmation is technically enforced. In an email-marketing skill, this mismatch is dangerous because an agent or integrator may rely on the documentation and trigger unintended outbound mail, causing spam, reputational damage, or compliance issues.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README says the v2.1 fix requires always calling getLists first, verifying list_id, and checking recipient count before campaign creation, but the exposed workflow still presents createEmailMessage and createCampaign as independently callable operations. That inconsistency can let users or agent planners bypass the safety workflow and send to the wrong audience or only a single unintended recipient, undermining campaign integrity.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The skill is explicitly designed to transmit user and contact data to an external third-party API using an API key. In context this is expected functionality, but it is still a real data-exposure surface because recipient lists, email content, and campaign metadata leave the local trust boundary.

Content

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

md
All requests require the `SELZY_API_KEY` environment variable. Pass it as the `api_key` parameter.

**Base URL:** `https://api.selzy.com/en/api`

**Important:** All methods use `GET` with query parameters (Selzy API uses GET for all endpoints). URL-encode parameter values when needed.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The general request pattern sends requests to Selzy with query parameters, meaning operational and potentially sensitive data are transmitted to an external service. This is inherent to the integration, but it expands the exposure surface and may also leak sensitive values via logs, browser history, proxies, or monitoring systems if query strings contain secrets or personal data.

Content

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

General Request Pattern

bash
curl "https://api.selzy.com/en/api/{METHOD}?format=json&api_key=$SELZY_API_KEY&{params}"

Response Format:

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

Creating a list on an external email-marketing platform is expected behavior, but it still performs state-changing transmission to a third party. In the context of marketing automation, such calls can create unauthorized campaign infrastructure or expose business metadata externally if triggered without proper approval.

Content

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

Create a new contact list.

bash
curl "https://api.selzy.com/en/api/createList?format=json&api_key=$SELZY_API_KEY&title=VIP%20Customers"

Response: {"result": {"id": 12345}}

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The importContacts example transmits personal data such as names and email addresses to an external provider. This is expected functionality, but it is a genuine sensitive-data transfer that can create privacy, consent, and compliance risks if contacts are uploaded without appropriate legal basis or user approval.

Content

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

Bulk import contacts into a list.

bash
curl "https://api.selzy.com/en/api/importContacts?format=json&api_key=$SELZY_API_KEY&field_names[]=email&field_names[]=Name&data[][]=john@example.com&data[][]=John&data[][]=jane@example.com&data[][]=Jane&list_ids=12345&overwrite=2"

| Parameter | Description |

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The subscribe example sends a user's email and profile fields to an external mailing platform, which is a sensitive outbound transfer. Because subscription state affects marketing consent and communications, misuse can lead to unauthorized enrollment and regulatory exposure.

Content

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

Add a single contact with opt-in control.

bash
curl "https://api.selzy.com/en/api/subscribe?format=json&api_key=$SELZY_API_KEY&list_ids=12345&fields[email]=user@example.com&fields[Name]=Alice&double_optin=3"

double_optin values:

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
90% confidence
Finding

The skill documents subscription modes that allow adding contacts with no confirmation or forcing them as already confirmed. In a marketing context this enables autonomous or low-friction enrollment into mailing lists, which can lead to unauthorized messaging, spam complaints, and regulatory violations.

Content

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

text

**double_optin values:**
- `0` = no confirmation
- `3` = send confirmation email
- `4` = already confirmed (force subscribe)

External Transmission

Medium
Category
Data Exfiltration
Confidence
78% confidence
Finding

The exclude example sends contact identifiers to a third-party service to change subscription status. Although expected, it is still an external transmission of personal data and a state-changing action that can affect user communications rights.

Content

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

Unsubscribe/remove a contact.

bash
curl "https://api.selzy.com/en/api/exclude?format=json&api_key=$SELZY_API_KEY&contact_type=email&contact=user@example.com"

2.4 Get Contact — getContact

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The getContact example transmits an email address to a third-party API for lookup, exposing personal data outside the local environment. Even though this is core functionality, the lookup can reveal or retrieve subscriber information and therefore carries privacy risk.

Content

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

Get contact details by email.

bash
curl "https://api.selzy.com/en/api/getContact?format=json&api_key=$SELZY_API_KEY&email=user@example.com"

2.5 Create Custom Field — createField

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The createEmailMessage example transmits campaign content, sender identity, and targeting metadata to an external provider via query parameters. This is sensitive operational data, and using GET increases the chance of leakage through logs, analytics, proxies, and intermediary infrastructure.

Content

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

Create an email template for campaigns.

bash
curl "https://api.selzy.com/en/api/createEmailMessage?format=json&api_key=$SELZY_API_KEY&sender_name=My%20Store&sender_email=news@yourdomain.com&subject=Summer%20Sale%20🔥&body=<h1>Hello!</h1><p>Check%20out%20our%20deals</p>&list_id=12345"

| Parameter | Required | Description |

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

Updating an email message sends campaign metadata to an external service and mutates state there. This is expected, but still a real external transmission and control surface that could be abused to alter campaign content without proper approval.

Content

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

Modify an existing email template.

bash
curl "https://api.selzy.com/en/api/updateEmailMessage?format=json&api_key=$SELZY_API_KEY&id=67890&subject=Updated%20Subject"

3.3 Get Message — getMessage

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

Creating a reusable email template sends content to a third-party platform and changes external state. That is intended behavior, but still introduces exposure of proprietary campaign material and possible misuse if invoked without review.

Content

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

Create a reusable template (separate from messages).

bash
curl "https://api.selzy.com/en/api/createEmailTemplate?format=json&api_key=$SELZY_API_KEY&name=Welcome%20Series&subject=Welcome!&body=<h1>Welcome {{Name}}!</h1>"

3.6 Get Template — getTemplate

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The createCampaign example triggers outbound email campaign execution through a third-party service, a high-impact state-changing external action. In context, misuse could send bulk communications to large contact lists, with business, reputational, and compliance consequences.

Content

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

Create and schedule a campaign.

bash
curl "https://api.selzy.com/en/api/createCampaign?format=json&api_key=$SELZY_API_KEY&message_id=67890&start_time=2026-02-10%2010:00:00&timezone=Europe/Moscow&track_read=1&track_links=1"

| Parameter | Required | Description |

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The example hard-codes Europe/Moscow and elsewhere Europe/Belgrade without requiring user confirmation of locale or timezone. In an email-campaign skill, this can cause messages to be sent at unintended times, potentially violating user expectations, harming campaigns, or triggering compliance and business-process issues.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
74% confidence
Finding

Canceling a campaign is a state-changing external action that affects communications and business processes. While not inherently malicious, it can disrupt operations if triggered without strong authorization and confirmation.

Content

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

Cancel a scheduled campaign before it sends.

bash
curl "https://api.selzy.com/en/api/cancelCampaign?format=json&api_key=$SELZY_API_KEY&campaign_id=11111"

4.3 Get Campaign Status — getCampaignStatus

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill repeatedly documents a hard safety limit of 1 campaign creation per hour, but this instruction says to proceed if the last campaign was created more than 60 seconds ago. That contradiction can cause an agent to violate the platform's anti-abuse threshold, leading to account suspension and unintended high-volume outbound email activity.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

Although presented as a negative example, this URL still illustrates sending API keys and HTML content in a GET query string to a third party. That pattern risks leakage of credentials and message content through logs and intermediaries even when the example is meant to teach a pitfall.

Content

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

bash
# Missing list_id — Selzy sends to 1 contact by default!
curl "https://api.selzy.com/en/api/createEmailMessage?format=json&api_key=$KEY&sender_name=My+Store&sender_email=me@example.com&subject=Sale&body=<h1>Sale!</h1>"

Result: Campaign #327590492 sent to 1 recipient instead of 4 contacts in list.

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This example sends sender identity, subject, and HTML body to the external service via a GET URL, exposing both sensitive operational data and the API key in the query string. In practice this can leak campaign content and credentials into logs or monitoring systems.

Content

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

md
# Response: [{"id": 12345, "title": "My first list", "count": 4}]

# Step 2: Create message WITH list_id
curl "https://api.selzy.com/en/api/createEmailMessage?format=json&api_key=$KEY&sender_name=My+Store&sender_email=me@example.com&subject=Sale&body=<h1>Sale!</h1>&list_id=12345"
# Response: {"result": {"message_id": 67890}}

# Step 3: Create campaign

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The example triggers actual campaign creation through an external provider, a high-impact outbound action capable of emailing many recipients. In the context of this skill, unauthorized or mistaken use has direct business and compliance consequences.

Content

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

md
# Response: {"result": {"message_id": 67890}}

# Step 3: Create campaign
curl "https://api.selzy.com/en/api/createCampaign?format=json&api_key=$KEY&message_id=67890"
# Response: {"result": {"campaign_id": 11111}}

# Result: Campaign sent to ALL 4 contacts ✅

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The error-handling table advises retrying after 1-2 seconds on HTTP 429, which conflicts with the stated hard limit for createCampaign operations. If applied to campaign creation, this guidance could trigger repeated abusive retries against a protected write endpoint and increase the risk of account blocking.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The quick-test command instructs users to place the API key directly into a URL query string. Even as a test, this promotes a practice that can leak credentials via shell history, logs, proxy records, and screenshots.

Content

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

Verify API access:

bash
# Check connection
curl "https://api.selzy.com/en/api/getLists?format=json&api_key=YOUR_KEY"

# Check verified senders
curl "https://api.selzy.com/en/api/getSenderEmails?format=json&api_key=YOUR_KEY"

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This test example likewise embeds the API key in a URL, normalizing insecure handling of credentials during external requests. The risk is credential disclosure through local and network logging surfaces.

Content

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

md
curl "https://api.selzy.com/en/api/getLists?format=json&api_key=YOUR_KEY"

# Check verified senders
curl "https://api.selzy.com/en/api/getSenderEmails?format=json&api_key=YOUR_KEY"

# Test campaign stats (replace ID)
curl "https://api.selzy.com/en/api/getCampaignCommonStats?format=json&api_key=YOUR_KEY&campaign_id=123456"

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This test command again places the API key in the request URL, which may expose credentials through shell history and observability tooling. Repetition of this pattern in documentation increases the chance users will copy unsafe practices into production automation.

Content

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

Static analysis

No suspicious patterns detected.