Back to skill

Security audit

Lead Gen + CRM Pipeline

Security checks for vulnerabilities and agentic risk

Overview

The skill largely matches its lead-generation purpose, but it can send outreach emails, write CRM records, store credentials and lead data, and contact user-controlled destinations without enough enforced safeguards.

Review this skill before installing. Use it only in a controlled workspace, keep API tokens out of committed config files, restrict file permissions, validate CRM tenant and lead-domain values, run outreach only after explicit human review, and confirm templates include required opt-out and sender information. Avoid unattended campaign sending until approval and compliance checks are enforced in code.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/push-to-crm.sh:93
Finding

Credential and Lead Data Disclosure Through Pipedrive Endpoint Injection

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/enrich-leads.sh:85
Finding

Server-Side Request Forgery During Lead Website Enrichment

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/init-workspace.sh:8
Finding

Plaintext Service Credentials Created Without Restrictive File Permissions

Content
View full analysis
"$BASE_DIR/config.json" << 'EOF' { "hunter_api_key": "", "default_crm": "hubspot", "crm": { "hubspot": { "api_key": "", "pipeline_id": "", "stage_id": "" }, "pipedrive": { "api_key": "", "domain": "" }, "zoho": { "access_token": "", "refresh_token": "" } }, "email": { "provider": "sendgrid", "sendgrid_api_key": "", "smtp": { "host": "", "port": 587, "user": "", "pass": "" }, "from_name": "", "from_email": "", "daily_limit": 50, "delay_between_emails_sec": 30 }, ``` ### Technical Analysis The generated `config.json` is explicitly designed to store Hunter, HubSpot, Pipedrive, Zoho, SendGrid, and SMTP credentials in plaintext. The initialization script does not establish a restrictive `umask` or apply `chmod 600` after creating the file. Under a common `umask` of `022`, shell redirection creates the file with mode `0644`, allowing other local users to read it. The containing workspace directories are also created without explicit restrictive permissions. ### Attack Path 1. A user initializes the workspace. 2. The script creates `config.json` according to the caller's current `umask`. 3. The user populates the placeholder fields with real API tokens or an SMTP password. 4. If the resulting mode permits group or world access, another local user or process reads the file. 5. The exposed credentials are reused against the corresponding external services. ### Impact Assessment Credential theft can grant access to email-sending infrastructure, CRM records, lead-enrichment services, and potentially long-lived Zoho sessions through a refresh token. The precise privileges depend on each credential's scopes, but compromise can result in unauthorized email delivery, CRM mo ...[truncated 57 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/create-campaign.sh:21
Finding

Path Traversal in Campaign, Template, and Lead-Set Identifiers

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send-campaign.sh:69
Finding

Documented Human Approval and Email Compliance Controls Are Not Enforced

Content
View full analysis
= daily_limit: print(f"\n ⚠️ Daily limit reached ({daily_limit}). Remaining will send tomorrow.") break subject = template["subject"] body = template["body"] for key in ["first_name", "last_name", "company_name", "domain"]: subject = subject.replace(f"{{{key}}}", r.get(key, "")) body = body.replace(f"{{{key}}}", r.get(key, "")) resp = requests.post( "https://api.sendgrid.com/v3/mail/send", headers={ "Authorization": f"Bearer {sendgrid_key}", "Content-Type": "application/json", }, json={ "personalizations": [{"to": [{"email": r["email"]}]}], "from": {"email": from_email, "name": fr ...[truncated 2358 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

If the skill description promises broad CRM and outreach automation while actual behavior is narrower and includes outbound email via SendGrid without clearly declared permissions, users may approve or invoke the skill under false assumptions. That can lead to unauthorized external transmission of lead/contact data or email sending beyond what the manifest transparently discloses.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the skill description promises broad CRM and outreach automation while actual behavior is narrower and includes outbound email via SendGrid without clearly declared permissions, users may approve or invoke the skill under false assumptions. That can lead to unauthorized external transmission of lead/contact data or email sending beyond what the manifest transparently discloses.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/crm-setup.md (reported line 8)May include surrounding context.

Get API Key

  1. Go to Settings → Integrations → Private Apps
  2. Create a private app with scopes: crm.objects.contacts.write, crm.objects.deals.write
  3. Copy the access token

Configure

json

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/crm-setup.md (reported line 53)May include surrounding context.

md
## Zoho CRM

### Get Access Token
1. Go to https://api-console.zoho.com/
2. Create a Self Client
3. Generate token with scope: `ZohoCRM.modules.leads.CREATE,ZohoCRM.modules.contacts.CREATE`

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises workflows that inherently require network, filesystem, and likely secret access, but it does not declare an explicit tool scope or permission boundary. That makes it easier for an agent runtime to over-grant capabilities or for users to misunderstand the operational reach of the skill, increasing the chance of unintended data access or outbound actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation guidance is extremely broad and overlaps with many normal sales and CRM tasks, which raises the risk that the skill is invoked in situations involving sensitive customer or prospect data without deliberate user intent. In a skill that can scrape, enrich, sync to CRMs, and send outreach, ambiguous triggering materially increases the chance of privacy-impacting or externally visible actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill handles collection, enrichment, storage, and third-party transmission of personal and business contact data, yet the documentation gives only cursory compliance notes and does not clearly explain consent, lawful basis, retention, or third-party sharing risks. In this context, missing privacy warnings are significant because the workflows directly encourage scraping, enrichment, CRM upload, and outreach at scale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The guide shows users placing live CRM API credentials directly into a JSON configuration example without any warning about secret handling, storage, rotation, or avoiding commits to source control. In an automation skill that orchestrates CRM and outreach actions, this increases the chance users will hardcode reusable tokens in files that may be logged, shared, or checked into repositories, leading to unauthorized CRM access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The CSV fallback documents that lead data will be exported to a local file but provides no warning that the file may contain sensitive personal or business contact data. In a lead-generation/CRM context, writing prospect data to disk without retention, access-control, or cleanup guidance can cause unintended disclosure through shared workspaces, backups, or accidental attachment/sharing.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/discover-leads.sh (reported line 64)May include surrounding context.

sh
try:
    resp = requests.get(
        "https://api.search.brave.com/res/v1/web/search",
        headers={"X-Subscription-Token": brave_key},
        params={"q": search_query, "count": min(count, 20)},
        timeout=15,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script sends the lead's domain to Hunter.io and later fetches the company's website for enrichment, which transmits user-managed lead data over the network. Although there are progress prints, there is no explicit disclosure, confirmation, or comment warning that external services will receive lead information.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/enrich-leads.sh (reported line 58)May include surrounding context.

sh
if hunter_key and domain:
        try:
            resp = requests.get(
                "https://api.hunter.io/v2/domain-search",
                params={"domain": domain, "api_key": hunter_key},
                timeout=10,
            )

Dynamic Request Target

Medium
Category
Server-Side Request Forgery
Confidence
96% confidence
Finding

The script builds a request target directly from lead-controlled domain data and performs a server-side fetch without validation. An attacker who can supply or modify lead JSON could cause requests to arbitrary hosts, including internal services or cloud metadata endpoints via DNS rebinding or crafted hostnames, turning the agent into an SSRF primitive.

Content

Scanner excerpt · scripts/enrich-leads.sh (reported line 88)May include surrounding context.

sh
# Basic web scrape for additional signals
    if domain:
        try:
            resp = requests.get(f"https://{domain}", timeout=8, headers={"User-Agent": "ReighlanLeadBot/1.0"})
            if resp.status_code == 200:
                text = resp.text.lower()
                # Tech signals

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

After writing the enriched record, the script removes the original file from the raw directory. This is an irreversible file operation, but there is no confirmation prompt or explicit warning that running the script will delete source lead files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This shell script writes a config.json file that includes fields for API keys, access tokens, refresh tokens, and SMTP credentials. Although it logs that the file was created, it does not warn the user that sensitive secrets will be stored in this workspace path, which is a user-disclosure gap for credential-related file creation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/push-to-crm.sh (reported line 61)May include surrounding context.

sh
# Create contact
        try:
            resp = requests.post(
                "https://api.hubapi.com/crm/v3/objects/contacts",
                headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
                json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/send-campaign.sh (reported line 109)May include surrounding context.

sh
# Create contact
        try:
            resp = requests.post(
                "https://api.hubapi.com/crm/v3/objects/contacts",
                headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
                json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/push-to-crm.sh (reported line 61)May include surrounding context.

sh
# Create contact
        try:
            resp = requests.post(
                "https://api.hubapi.com/crm/v3/objects/contacts",
                headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
                json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/push-to-crm.sh (reported line 62)May include surrounding context.

sh
# Create contact
        try:
            resp = requests.post(
                "https://api.hubapi.com/crm/v3/objects/contacts",
                headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
                json={
                    "properties": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/push-to-crm.sh (reported line 100)May include surrounding context.

sh
return False
        
        try:
            resp = requests.post(
                f"https://{domain}.pipedrive.com/api/v1/persons",
                params={"api_token": api_key},
                json={

Dynamic Request Target

Medium
Category
Server-Side Request Forgery
Confidence
93% confidence
Finding

The Pipedrive request target is constructed from a configurable domain value without strict validation: https://{domain}.pipedrive.com/api/v1/persons. If an attacker can influence config or environment variables, they may redirect requests to attacker-controlled or unintended subdomains, causing unauthorized transmission of lead data and API usage against the wrong tenant. In a skill that automates handling of large volumes of lead/contact data, this increases the risk of silent data leakage at scale.

Content

Scanner excerpt · scripts/push-to-crm.sh (reported line 100)May include surrounding context.

sh
return False
        
        try:
            resp = requests.post(
                f"https://{domain}.pipedrive.com/api/v1/persons",
                params={"api_token": api_key},
                json={

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The csv branch appends lead contact data to reports/leads-export.csv, which is a file write involving user/business data. While network pushes are part of the script's stated purpose and are visibly announced, this local export path has no specific warning, confirmation, or explanatory comment/disclosure near the operation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/send-campaign.sh (reported line 109)May include surrounding context.

sh
body = body.replace(f"{{{key}}}", r.get(key, ""))
    
    try:
        resp = requests.post(
            "https://api.sendgrid.com/v3/mail/send",
            headers={
                "Authorization": f"Bearer {sendgrid_key}",

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/send-campaign.sh (reported line 110)May include surrounding context.

sh
try:
        resp = requests.post(
            "https://api.sendgrid.com/v3/mail/send",
            headers={
                "Authorization": f"Bearer {sendgrid_key}",
                "Content-Type": "application/json",