Phone Caller
WarnAudited by ClawScan on May 10, 2026.
Overview
The skill largely does what it claims, but its interactive phone server exposes unauthenticated public webhooks and stores/serves call data in ways users should review before installing.
Review before installing. Use dedicated provider keys, confirm every phone number and call purpose, avoid campaign use unless legally compliant, validate Twilio webhook signatures, restrict the public tunnel, fix the CALLER_PUBLIC_URL setup mismatch, and clean up /tmp audio/transcript files after calls.
Findings (7)
Artifact-based informational review of SKILL.md, metadata, install specs, static scan signals, and capability signals. ClawScan does not execute the skill or run runtime probes.
The agent can place real calls on the user's Twilio account when invoked.
The script can initiate real outbound Twilio calls to a user-supplied phone number. This is expected for the skill, but it is high-impact external communication and can incur cost.
call = client.calls.create(
from_=TWILIO_FROM,
to=args.to,
url=f"{url}/call/start?{params}"Only use it with explicit user approval for the destination number, message/persona, and timing, especially for reservations, appointments, or campaign-like use.
Misconfigured or over-scoped credentials could allow unwanted calls, API charges, or exposure of phone conversation content to providers.
The skill requires high-value provider credentials that can spend money, place calls, and process conversation content. This is purpose-aligned, but the registry metadata declares no required env vars or primary credential.
ELEVENLABS_API_KEY ... TWILIO_ACCOUNT_SID ... TWILIO_AUTH_TOKEN ... TWILIO_PHONE_NUMBER ... OPENAI_API_KEY
Use dedicated, least-privilege Twilio/OpenAI/ElevenLabs credentials where possible, monitor usage, and revoke keys if the skill is no longer needed.
Anyone who learns or guesses the tunnel URL could submit fake webhook traffic, consume OpenAI/ElevenLabs credits, manipulate call state, or inject content into summaries.
The public-facing webhook directly trusts POST parameters and sends speech text into GPT/TTS processing. The supplied code does not show Twilio request signature validation or another authentication check.
@app.route("/call/respond", methods=["POST"])
def call_respond():
call_sid = request.values.get("CallSid", "unknown")
user_said = request.values.get("SpeechResult", "").strip()
...
ai_reply = gpt_reply(call_sid, user_said)
...
app.run(host="0.0.0.0", port=PORT, debug=False)Validate Twilio signatures on all webhook routes, use hard-to-guess tunnel URLs, add an application secret, and reject requests that are not from Twilio.
A requester who knows or guesses a temporary filename could retrieve local temporary files, including potentially sensitive call artifacts.
The audio endpoint falls back to serving any matching filename in /tmp, not only files created and tracked by the skill. In interactive mode this endpoint is intended to be reachable through the public tunnel.
@app.route("/audio/<filename>")
def serve_audio(filename):
path = audio_files.get(filename) or f"/tmp/{filename}"
if os.path.exists(path):
return send_file(path, mimetype="audio/mpeg")Serve only files in a dedicated skill-owned directory, require the filename to exist in the audio_files map, and avoid exposing arbitrary /tmp paths.
Private call details may remain on disk after the call and could be read by other local processes or exposed through overly broad file serving.
The server stores the call summary and full transcript in /tmp, but SKILL.md only mentions that a summary is sent via iMessage and does not describe local transcript retention or cleanup.
log_path = f"/tmp/call_{call_sid[:8]}.txt"
with open(log_path, "w") as f:
f.write(f"SUMMARY\n{summary}\n\nTRANSCRIPT\n{transcript}")Document transcript storage, store logs in a private skill-owned directory with restrictive permissions, and add cleanup or an opt-out.
The skill may send messages from the user's local messaging setup and may fail or behave unexpectedly if the imsg tool is missing or configured differently.
The server invokes a local imsg command to send the call summary. Sending a summary is disclosed, but the required binary is not declared in the metadata or install requirements.
subprocess.run(["imsg", "send", "--to", MASTER_PHONE, "--text", msg], capture_output=True)
Declare the required imsg dependency, make summary sending optional, and confirm MASTER_PHONE before use.
A scheduled call could occur at a later time, potentially causing surprise, cost, or unwanted contact if not tracked.
The skill documents a user-created cron job that can make a future phone call. This is disclosed and user-directed, but it is persistent behavior that may run later without active review.
Use macOS cron for timed calls: ... crontab -e 45 8 24 2 * python3 /path/to/scripts/one_way_call.py --to "+1..." --text "Good morning!"
Use cron scheduling only for calls the user explicitly approves, log scheduled jobs, and remove the cron entry after it is no longer needed.
