Back to skill

Security audit

Hlp Ghl Api

Security checks for vulnerabilities and agentic risk

Overview

This skill is aimed at GoHighLevel CRM work, but it gives agents direct live write and SMS commands without approval safeguards.

Review before installing. Use a least-privilege GoHighLevel API key, separate read-only use from write and SMS actions, and require explicit human confirmation with the exact recipient, record, and payload before creating records, changing stages/tags, triggering workflows, adding notes, or sending messages. Harden the commands with jq-built JSON payloads and proper URL encoding before production use.

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

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:24
Finding

Unsafe Shell Interpolation in CRM Request Payloads

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 24–27 and 36–39
Vulnerability Type: Shell argument injection and unsafe JSON construction
Risk Level: Medium

Vulnerable Code

sh
curl -s -X POST "https://services.leadconnectorhq.com/contacts/" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"firstName":"$FIRST","lastName":"$LAST","email":"$EMAIL","phone":"$PHONE","locationId":"'$GHL_LOCATION_ID'","tags":["$TAGS"],"source":"$SOURCE"}' | jq .
sh
curl -s -X POST "https://services.leadconnectorhq.com/opportunities/" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"pipelineId":"$PIPELINE_ID","locationId":"'$GHL_LOCATION_ID'","name":"$DEAL_NAME","stageId":"$STAGE_ID","contactId":"$CONTACT_ID","status":"open"}' | jq .

Technical Analysis

The JSON request bodies are assembled through inconsistent shell quoting. Most variables, including $FIRST, $EMAIL, and $CONTACT_ID, appear inside single-quoted strings and therefore are not expanded by a POSIX-compatible shell. They are transmitted as literal variable names rather than their intended values.

In contrast, $GHL_LOCATION_ID is placed outside the single-quoted portions and expanded without double quotes:

sh
... "locationId":"'$GHL_LOCATION_ID'" ...

Because this expansion is unquoted, shell word splitting and pathname expansion apply. A malformed or attacker-controlled value containing whitespace, wildcard characters, or strings resembling command-line options can split the intended -d argument into multiple arguments. Additional resulting arguments may then be interpreted by curl as options or URLs.

The issue does not directly invoke shell metacharacters embedded in the variable as executable syntax, because shell parsing occurs before parameter expansion. Nevertheless, argument injection into curl remains possible and c ...[truncated 1721 chars]

Remediation
View remediation

Remediation Suggestions

Construct every JSON payload with a JSON-aware utility such as jq, and double-quote every shell expansion. Do not interpolate values directly into JSON strings.

A hardened contact-creation example is:

sh
payload=$(jq -n \
  --arg firstName "$FIRST" \
  --arg lastName "$LAST" \
  --arg email "$EMAIL" \
  --arg phone "$PHONE" \
  --arg locationId "$GHL_LOCATION_ID" \
  --arg tag "$TAGS" \
  --arg source "$SOURCE" \
  '{
    firstName: $firstName,
    lastName: $lastName,
    email: $email,
    phone: $phone,
    locationId: $locationId,
    tags: [$tag],
    source: $source
  }')

curl --fail-with-body -sS -X POST \
  "https://services.leadconnectorhq.com/contacts/" \
  -H "Authorization: Bearer $GHL_API_KEY" \
  -H "Version: 2021-07-28" \
  -H "Content-Type: application/json" \
  --data-binary "$payload" |
  jq .

Apply the same pattern to opportunity creation and every other JSON body. In addition:

  1. Validate GHL_LOCATION_ID against its expected identifier syntax before use.
  2. Use --data-binary "$payload" so the entire body is passed as one argument.
  3. Use --fail-with-body -sS so HTTP and transport failures are visible.
  4. URL-encode all values used in query strings instead of directly concatenating environment variables.
  5. Validate identifiers used in URL paths to prevent path manipulation.
  6. Keep GHL_API_KEY scoped to the minimum CRM permissions required and rotate it if unintended disclosure is suspected.
  7. Consider using a dedicated API client or wrapper script rather than instructing users or Agents to copy shell commands containing credentials.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill exposes live write operations against CRM records and outbound SMS capability without any guardrails, confirmation steps, or warning that these actions modify production customer data. In an agent setting, this can cause unauthorized record changes, accidental lead reassignment, workflow triggering, and real customer communications based solely on prompt input.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This command transmits user-supplied contact data to an external CRM and creates or updates records in a live system. Because the JSON body is assembled with shell interpolation, untrusted values can also break payload structure or cause unintended data submission, while the main risk is unauthorized modification and exfiltration of PII to an external service.

Content

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

md
## Create or Update Contact

curl -s -X POST "https://services.leadconnectorhq.com/contacts/" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"firstName":"$FIRST","lastName":"$LAST","email":"$EMAIL","phone":"$PHONE","locationId":"'$GHL_LOCATION_ID'","tags":["$TAGS"],"source":"$SOURCE"}' | jq .

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

This request modifies live contact metadata in an external CRM by adding tags, which can alter routing, segmentation, and automations. In this business context, tags are operationally meaningful for lead-gen workflows, so accidental or unauthorized tagging can trigger downstream actions and mis-handle customer records.

Content

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

md
## Add Tags to Contact

curl -s -X POST "https://services.leadconnectorhq.com/contacts/$CONTACT_ID/tags" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"tags":["$TAG1","$TAG2"]}' | jq .

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This command creates pipeline opportunities in the external CRM, which can affect sales reporting, assignment queues, and automated workflows. In a real-estate lead generation environment, creating deals in the wrong pipeline or for the wrong contact can materially disrupt operations and expose customer information to unintended staff.

Content

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

md
## Create Opportunity (Pipeline Deal)

curl -s -X POST "https://services.leadconnectorhq.com/opportunities/" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"pipelineId":"$PIPELINE_ID","locationId":"'$GHL_LOCATION_ID'","name":"$DEAL_NAME","stageId":"$STAGE_ID","contactId":"$CONTACT_ID","status":"open"}' | jq .

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

Moving an opportunity stage changes the status of a live sales record in an external system and may trigger automations, notifications, or reporting changes. Given the named production pipelines for real-estate leads, incorrect stage transitions can directly impact customer handling and business decisions.

Content

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

md
## Move Opportunity Stage

curl -s -X PUT "https://services.leadconnectorhq.com/opportunities/$OPP_ID/status" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"stageId":"$NEW_STAGE_ID"}' | jq .

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This command sends outbound SMS messages to real contacts through a live conversations API, creating direct external communication risk. In addition to privacy and reputational harm, misuse can result in spam, regulatory exposure, or contacting customers without consent, and the skill provides no warning, approval gate, or policy checks.

Content

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

md
## Send SMS via Conversations API

curl -s -X POST "https://services.leadconnectorhq.com/conversations/messages" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"type":"SMS","contactId":"$CONTACT_ID","message":"$MESSAGE"}' | jq .

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

This request writes notes to a live customer record in an external CRM, which can store sensitive or incorrect information permanently and influence future staff decisions. Because note text is fully user-controlled and no validation or confirmation is described, the skill increases the risk of accidental disclosure, misinformation, or inappropriate data entry.

Content

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

md
## Add Note to Contact

curl -s -X POST "https://services.leadconnectorhq.com/contacts/$CONTACT_ID/notes" \
  -H "Authorization: Bearer $GHL_API_KEY" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  -d '{"body":"$NOTE_TEXT"}' | jq .