Back to skill

Security audit

Llc Phone

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate-looking AI phone-call skill, but its reference instructions include unsafe deployment patterns for billable calls, customer records, and caller audio that need review before use.

Review this before production use. Treat the code as incomplete reference material, not a secure drop-in server: add Twilio signature validation, authentication on outbound endpoints, strict request and tool-argument schemas, destination allowlists, spending/rate limits, record-level authorization, consent/notice language, and audit logging before connecting real phone numbers, customers, or campaigns.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
docs/03-prewarm-outbound.md:43
Finding

Unauthenticated Outbound Endpoint Permits Arbitrary Billable Calls

Content
View full analysis
{ const { to, prospectContext } = req.body; const callId = crypto.randomUUID(); ``` ```javascript // Place the call const call = await twilioClient.calls.create({ from: process.env.TWILIO_PHONE_NUMBER, to, twiml: ``, statusCallback: `https://${DOMAIN}/call-status`, statusCallbackMethod: "POST", statusCallbackEvent: ["completed", "no-answer", "busy", "failed"], }); session.callSid = call.sid; callSidToCallId.set(call.sid, callId); res.json({ callSid: call.sid, callId }); ``` ### Technical Analysis The reference handler accepts the destination number and prospect context directly from the HTTP request body, then uses privileged Twilio credentials to place a call. No authentication, campaign-level authorization, E.164 validation, destination restrictions, request schema validation, quota, or rate limit is demonstrated. Because the endpoint performs a billable external action, possession of network access to the route is sufficient to exercise the application's Twilio privileges. The untrusted `prospectContext` is also passed into the session prompt elsewhere in the handler, creating an additional caller-controlled model-context boundary. ### Attack Path 1. An attacker identifies the publicly reachable `/outbound-call` endpoint. 2. The attacker submits a POST request containing an attacker-selected `to` number, potentially including premium-rate or high-cost international destinations. 3. The server creates an OpenAI session and invokes `twilioClient.calls.create()` with its configured Twilio credentials. 4. The attacker repeats the re ...[truncated 830 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
docs/04-inbound-modes.md:19
Finding

Twilio Webhooks Are Processed Without Signature Validation

Content
View full analysis
{ const { CallSid, From, To } = req.body; const callId = CallSid; const modeConfig = getModeConfig(To, From); const openaiWs = new WebSocket( "wss://api.openai.com/v1/realtime?model=gpt-realtime-1.5", { headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` } } ); const session = { openaiWs, greetingBuffer: [], greetingComplete: false, streamSid: null, twilioWs: null, callSid: CallSid, status: "warming", mode: modeConfig.mode, callerNumber: From, createdAt: Date.now(), }; ``` ```javascript // Twilio status webhook app.post("/call-status", (req, res) => { const callId = callSidToCallId.get(req.body.CallSid); if (callId) { const session = preWarmSessions.get(callId); if (session?.openaiWs.readyState === WebSocket.OPEN) session.openaiWs.close(); preWarmSessions.delete(callId); callSidToCallId.delete(req.body.CallSid); } res.sendStatus(200); }); ``` ### Technical Analysis The handlers trust `CallSid`, `From`, `To`, and call-status fields supplied in the HTTP body without verifying the `X-Twilio-Signature` header. No repository guidance was found for validating Twilio webhook authenticity. The inbound handler uses these values to select the operating mode, establish an authenticated and potentially billable OpenAI connection, associate caller identity with a session, and potentially trigger CRM lookup behavior. The status callback uses an unverified Call SID to close and delete sessions. A Call SID is an identifier, not an authentication credential. Even where an attacker does not know a live identifier, forged inbound requests can still create resource-consuming sessions. ...[truncated 1582 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
docs/03-prewarm-outbound.md:131
Finding

Media WebSocket Sessions Are Bound Using Only an Untrusted Call Identifier

Content
View full analysis
{ const callId = req.query.callId; const session = preWarmSessions.get(callId); if (!session || session.status === "failed") { handleColdConnect(twilioWs, req); return; } session.twilioWs = twilioWs; twilioWs.on("message", (message) => { const data = JSON.parse(message); if (data.event === "start") { session.streamSid = data.start.streamSid; if (session.greetingComplete) flushGreetingBuffer(session); ``` ```javascript res.type("text/xml").send( '' ); ``` ### Technical Analysis The WebSocket handler obtains `callId` from a query parameter and uses it as the sole basis for selecting a live session. It immediately assigns the connecting socket to `session.twilioWs`. The example does not authenticate the WebSocket upgrade, use a separate one-time capability, or verify that the subsequent Twilio `start` event's Account SID and Call SID match the stored session. For inbound calls, the Twilio Call SID itself is placed in the WebSocket URL. For outbound calls, the identifier is a random UUID, which reduces guessability but does not provide complete authentication. Identifiers may be disclosed through application responses, logs, monitoring systems, proxy logs, or referrers in surrounding infrastructure. The code also accepts `streamSid` from the first `start` message without proving that the sender is Twilio. Once the session enters the live state, media received on the socket is forwarded to OpenAI and generated media is sent back through the assigned socket. ### Attack Path 1. An attacker ...[truncated 1414 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
docs/05-async-tools.md:45
Finding

Untrusted Model Tool Arguments Directly Control Privileged Telephony and Business Operations

Content
View full analysis
One moment." + confName + "", }); // Dial agent into same conference await twilioClient.calls.create({ from: process.env.TWILIO_PHONE_NUMBER, to: agentNumber, twiml: "Transfer: " + introduction + "" + confName + "", }); } ``` ### Technical Analysis Tool names and arguments or ...[truncated 3000 chars]
Remediation
View remediation
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (10)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

md
| Snapshots | `websocket-server/snapshots/` |
| Service unit | your process supervisor unit file (systemd user unit, pm2 ecosystem file, etc.) |
| Logs | wherever you configured (stdout + journald, `/var/log/...`, pm2 logs, etc.) |
| .env | `websocket-server/.env` (contains `PORT`) |

## Reference Documents

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · docs/09-openclaw-config.md (reported line 139)May include surrounding context.

md
| Snapshots | `websocket-server/snapshots/` |
| Service unit | your process supervisor unit file (systemd user unit, pm2 ecosystem file, etc.) |
| Logs | wherever you configured (stdout + journald, `/var/log/...`, pm2 logs, etc.) |
| .env | `websocket-server/.env` (contains `PORT`) |

## Reference Documents

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file states that the skill supports receptionist and CSR flows, including caller lookup by phone, appointments, and notes, which implies handling personal and potentially sensitive customer data. The README does not include any warning or disclosure about privacy implications, consent requirements, or the transmission of call/customer data to OpenAI and Twilio.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill explicitly requires OpenAI and Twilio credentials and describes real-time phone-call infrastructure that transmits audio and metadata to external services, but it does not provide any user-facing warning about sensitive data handling, recording implications, or external transmission. In a telephony context, this omission matters because call content, phone numbers, and operational secrets may be exposed or mishandled by operators who are not alerted to the privacy and compliance risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file includes example logic for forwarding live caller audio from Twilio to OpenAI, which is a privacy-impacting data transmission. The surrounding documentation does not include any warning or disclosure that caller audio and related conversation data will be sent to a third-party API.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documented outbound flow sends live call audio and prospectContext to OpenAI and Twilio, but the design shown includes no consent, disclosure, or jurisdiction-aware notice mechanism before processing begins. In telephony and customer-service contexts, undisclosed recording or AI processing can create privacy, compliance, and legal exposure, especially where two-party consent, biometric voice handling, or vendor data-sharing rules apply.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · docs/04-inbound-modes.md (reported line 180)May include surrounding context.

Goals: 1) identify who is calling and what they need, 2) check if the right person is available (use check_availability), 3) transfer if available, 4) take a message with name, number, and reason if not. Keep responses natural and concise. Never leave silence > 20s without checking back in.

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The document explicitly instructs the system to perform a silent customer lookup using the caller's phone number and to greet them by name if found, without any warning about consent, notice, data minimization, or misidentification risks. In a phone-support context this can expose personal account data to the wrong caller, especially with shared, recycled, spoofed, or forwarded phone numbers, and normalizes privacy-sensitive processing as a default behavior.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% 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.

Content

Scanner excerpt · docs/05-async-tools.md (reported line 86)May include surrounding context.

output: JSON.stringify(result), }, })); // Do not automatically send response.create after every tool result. // In some realtime flows that creates duplicate or overlapping audio. }

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The prompt guidance explicitly instructs the AI to remain silent while add_call_note saves notes, with no user-facing disclosure that notes may be recorded or stored. In a live phone/customer-service context, hidden data capture can create privacy, consent, and compliance risk, especially if callers may share sensitive personal or account information.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
docs/04-inbound-modes.md:200