Back to skill

Security audit

TelCall Twilio

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it can place real paid phone calls and stores a Twilio auth token on disk without enough safeguards or confirmation guidance.

Review this skill before installing. Use a limited Twilio API key if possible, rotate it if exposed, and avoid running setup on shared or recorded terminals. Before each call, the agent should confirm the destination number, spoken message, and expected cost. Do not pass untrusted or markup-like text as the call message unless the script is fixed to escape TwiML/XML content.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.sh:55
Finding
Twilio authentication token stored in plaintext<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh`, lines 34 and 55–65 **Vulnerability Type**: Plaintext storage and visible entry of sensitive credentials **Risk Level**: Medium ### Vulnerable Code ```bash read -p "Auth Token: " auth_token ``` ```bash # Save configuration cat > "$CONFIG_FILE" << EOF { "account_sid": "$account_sid", "auth_token": "$auth_token", "from_number": "$from_number", "to_number": "$to_number" } EOF # Set secure permissions chmod 600 "$CONFIG_FILE" ``` ### Technical Analysis The Twilio Auth Token is entered through a normal terminal prompt, so its characters remain visible while the user types. The token is then stored persistently as plaintext in `twilio.json`. File mode `600` appropriately restricts access to the owning user, but it does not encrypt the secret or protect it from malicious processes running under that user, compromised user-level applications, exposed backups, or accidental copying of the configuration file. Because the Account SID and Auth Token are stored together, disclosure of this file provides reusable Twilio API credentials. The exact capabilities available to an attacker depend on the permissions and configuration of the affected Twilio account. ### Attack Path 1. A user runs `scripts/setup.sh` and enters the Twilio Auth Token at the visible prompt. 2. A nearby observer, terminal recording mechanism, or screen-capture process observes the token; alternatively, an attacker with access to files owned by the same user reads `twilio.json`. 3. The attacker extracts the Account SID and Auth Token. 4. The attacker authenticates directly to Twilio APIs with the stolen credentials. 5. The attacker performs operations allowed by the affected Twilio account, potentially including unauthorized calls that incur charges. ### Impact Assessment Successful exploitation exposes credentials associated with the user's Twilio account. An attacker may initiate unauthorized communicatio ...[truncated 286 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Read the Auth Token without terminal echo: ```bash read -s -p "Auth Token: " auth_token echo ``` - Prefer an operating-system credential store or dedicated secret manager rather than a plaintext JSON file. - If file-based storage is unavoidable, create the directory and file with restrictive permissions from the outset, such as by setting `umask 077` before creation. - Keep credentials out of backups, logs, diagnostics, and source-control repositories. - Consider using restricted API keys where Twilio supports them instead of a broadly privileged primary Auth Token. - Document credential revocation and rotation procedures for suspected exposure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/call.sh:36
Finding
User-controlled message permits TwiML/XML injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/call.sh`, lines 14 and 36–41 **Vulnerability Type**: XML injection into Twilio Markup Language **Risk Level**: Medium ### Vulnerable Code ```bash MESSAGE="$1" ``` ```bash # Create TwiML with the message # Language options: en-US, zh-CN, ja-JP, etc. TWIML="<Response><Say language=\"en-US\" voice=\"alice\">Emergency notification: ${MESSAGE}</Say></Response>" # URL encode the TwiML ENCODED_TWIML=$(echo "$TWIML" | jq -sRr @uri) ``` ### Technical Analysis The first command-line argument is treated as untrusted message content and interpolated directly into an XML document. The script does not escape XML-sensitive characters such as `&`, `<`, `>`, quotes, or apostrophes before constructing the TwiML. URI encoding the completed document does not neutralize XML markup. It only prepares the resulting value for transport. Once the request parameter is decoded, attacker-supplied XML can remain part of the TwiML document. An attacker who controls the message can close the intended `Say` element and insert additional syntactically valid TwiML elements. Less sophisticated input containing XML metacharacters can also make the document malformed and prevent the emergency call from operating correctly. ### Attack Path 1. An attacker gains the ability to invoke `call.sh` or influence the message passed to it through an integrating agent or automation. 2. The attacker supplies a crafted message containing closing XML tags and additional TwiML markup, for example a payload shaped like: ```text </Say><Pause length="10"/><Say>Injected content</Say><Say> ``` 3. The script interpolates the payload directly into the `Response` document. 4. The complete document is URI-encoded and submitted to Twilio. 5. After transport decoding, Twilio processes the attacker-influenced TwiML. 6. The injected verbs may alter the call flow, while malformed payloads may cause the call to fail. ### Impact Assessment Exploitation ca ...[truncated 495 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - XML-escape the message before inserting it into TwiML. - Prefer generating TwiML with an XML library that creates text nodes safely rather than assembling XML with shell string interpolation. - Ensure at minimum that `&`, `<`, `>`, `"`, and `'` are encoded appropriately for XML. - Apply a reasonable maximum message length to prevent excessively long or costly calls. - If the expected content is narrowly defined, enforce an allowlist of acceptable characters. - Add tests using XML metacharacters and attempted closing tags to verify that all supplied content remains inside the `Say` text node. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/setup.sh:55
Finding
Configuration JSON is constructed without escaping input values<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh`, lines 55–62 **Vulnerability Type**: Unsafe manual JSON construction **Risk Level**: Low ### Vulnerable Code ```bash # Save configuration cat > "$CONFIG_FILE" << EOF { "account_sid": "$account_sid", "auth_token": "$auth_token", "from_number": "$from_number", "to_number": "$to_number" } EOF ``` ### Technical Analysis The setup script constructs JSON by directly interpolating interactive input into a here-document. None of the values are JSON-escaped. A quote, backslash, control character, or newline can therefore terminate a string, produce malformed JSON, or add attacker-selected JSON properties. Although expected Twilio SIDs and telephone numbers have constrained formats, the script validates only that values are nonempty. It does not enforce the expected syntax. The Auth Token and all other fields can consequently contain characters that affect the JSON structure. The subsequent `call.sh` script reads these fields with `jq`. Malformed JSON can cause configuration loading to fail, while a carefully constructed object can affect the values returned for fields consumed by the call script. ### Attack Path 1. An attacker controls or convinces a user to enter a crafted value during setup. 2. The value contains JSON syntax such as quotes, commas, newlines, or additional property definitions. 3. The here-document writes the value without escaping it. 4. The resulting `twilio.json` is malformed or contains attacker-shaped fields. 5. A later invocation of `call.sh` processes the altered configuration with `jq`. 6. The call fails or uses manipulated account, source-number, destination-number, or token data. ### Impact Assessment The primary impact is configuration corruption and denial of service for emergency calls. If an attacker can influence setup values, the attacker may also redirect calls or cause the script to authenticate using substituted Twilio account informatio ...[truncated 240 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Generate the configuration with `jq` so every value is encoded as a JSON string: ```bash jq -n \ --arg account_sid "$account_sid" \ --arg auth_token "$auth_token" \ --arg from_number "$from_number" \ --arg to_number "$to_number" \ '{ account_sid: $account_sid, auth_token: $auth_token, from_number: $from_number, to_number: $to_number }' > "$CONFIG_FILE" ``` Additionally: - Validate the Account SID against Twilio's expected SID format. - Validate both telephone numbers as normalized E.164 numbers. - Validate token length and permitted characters without printing the token. - Check that `jq` succeeds before replacing an existing valid configuration. - Write to a restrictive temporary file and atomically rename it only after successful validation. - Set `umask 077` before creating files containing credentials. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (10)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill can invoke shell-based scripts (`setup.sh` and `call.sh`) but does not declare any explicit tool scope or permissions boundaries. This increases the chance that an agent or platform will execute shell actions without clear user consent or policy enforcement, which is especially risky because the skill triggers real-world phone calls and handles credentials.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill description and feature overview emphasize ease of making calls but do not prominently warn that it places real outbound phone calls, may incur charges, and may disclose message contents to third parties. Because this is a telephony skill using paid external infrastructure, missing warnings can mislead users into triggering costly or privacy-impacting actions without informed consent.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
2. Add your phone number
3. Complete verification via SMS or voice call

**Note:** Upgrade your account ($20 minimum) to call any number without verification.

## Setup
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation phrases are broad and natural-language based, such as 'Call me' and 'Emergency call', making accidental or ambiguous invocation plausible in normal conversation. In this skill's context, unintended activation can lead to real outbound calls, privacy exposure, and unexpected charges, so the risk is more serious than for a read-only skill.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "   Message: $MESSAGE"
echo ""

RESPONSE=$(curl -s -X POST "https://api.twilio.com/2010-04-01/Accounts/${ACCOUNT_SID}/Calls.json" \
    -u "${ACCOUNT_SID}:${AUTH_TOKEN}" \
    -d "To=${TO_NUMBER}" \
    -d "From=${FROM_NUMBER}" \
Confidence
70% 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
echo "   Message: $MESSAGE"
echo ""

RESPONSE=$(curl -s -X POST "https://api.twilio.com/2010-04-01/Accounts/${ACCOUNT_SID}/Calls.json" \
    -u "${ACCOUNT_SID}:${AUTH_TOKEN}" \
    -d "To=${TO_NUMBER}" \
    -d "From=${FROM_NUMBER}" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "=================================="
echo ""

# Create config directory
mkdir -p "$CONFIG_DIR"

# Check if config already exists
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.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script prompts for a Twilio Auth Token and writes it in plaintext to a persistent JSON file under the user's home directory without any warning about sensitive credential storage, rotation, or safer alternatives. Although chmod 600 reduces local exposure, plaintext long-lived API secrets on disk increase the risk of credential theft from local compromise, backups, sync tools, or accidental disclosure.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
EOF

# Set secure permissions
chmod 600 "$CONFIG_FILE"

echo ""
echo "✅ Configuration saved to: $CONFIG_FILE"
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The TwiML payload hard-codes `language="en-US"` for synthesized speech. This is a natural-language locale choice imposed by the skill, and the file does not offer a user opt-in or explain that the skill is intentionally limited to English.

Static analysis

No suspicious patterns detected.