Back to skill

Security audit

Amber — Phone-Capable Voice Agent

Security checks for vulnerabilities and agentic risk

Overview

Amber’s phone-assistant purpose is coherent and mostly disclosed, but its outbound-call confirmation gate can be bypassed by a caller-supplied MCP flag, so it needs review before real use.

Review and patch the outbound-call workflow before enabling real calls: require server-side, single-use approval state bound to the exact phone number and objective, or set AMBER_ENABLE_OUTBOUND_CALLS=false until fixed. Use a dedicated Twilio subaccount, dedicated OpenAI project key, BRIDGE_API_TOKEN, strict webhook validation, and clear caller consent/retention rules for logs, contacts, CRM memory, and transcript enrichment. Update flagged dependencies before production deployment.

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

Error
Location
runtime/src/mcp-server.ts:343
Finding
Client-controlled confirmation flag allows outbound call safeguards to be bypassed<![CDATA[ ## Vulnerability Details **File Location**: `runtime/src/mcp-server.ts:343-474` **Vulnerability Type**: Authorization and confirmation-state bypass **Risk Level**: High ### Vulnerable Code ```ts case 'make_call': { let { to, name: toName, objective, confirmed } = args as { to?: string; name?: string; objective: string; confirmed?: boolean }; if (!OUTBOUND_CALLS_ENABLED) { return { content: [{ type: 'text', text: 'Outbound calling is disabled because AMBER_ENABLE_OUTBOUND_CALLS=false is set. Remove it or set AMBER_ENABLE_OUTBOUND_CALLS=true, then restart Amber.', }], isError: true, }; } // Resolve name → phone number via contacts cache if (!to && toName) { const cachePath = path.join(__dirname, '..', 'contacts-cache.json'); if (!fs.existsSync(cachePath)) { return { content: [{ type: 'text', text: 'Contacts cache not found. Run `npm run sync-contacts` first.' }], isError: true }; } const cache = JSON.parse(fs.readFileSync(cachePath, 'utf8')); const contacts: any[] = cache.contacts || []; const q = toName.toLowerCase(); const matches = contacts.filter((c: any) => `${c.firstName} ${c.lastName}`.toLowerCase().includes(q) || c.firstName?.toLowerCase().includes(q) || c.lastName?.toLowerCase().includes(q) || c.nickname?.toLowerCase().includes(q) ).filter((c: any) => c.phones?.length > 0 || c.phone); if (matches.length === 0) { return { content: [{ type: 'text', text: `No contact found named "${toName}" with a phone number.` }], isError: true }; } if (matches.length > 1) { const names = matches.map((c: any) => `${c.firstName} ${c.lastName}`.trim() + ` (${(c.phones?.[0]?.number || c.phone)})` ).join('\n'); return { content: [{ type: 'text', text: ...[truncated 5439 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace the caller-supplied Boolean confirmation model with a server-enforced, two-phase approval workflow: 1. **Reject first-request confirmation** - Do not accept `confirmed: true` unless the server has already created a matching pending-call proposal. - Treat the Boolean as informational rather than authoritative. 2. **Create server-side pending-call state** - During the preview phase, store the normalized destination, resolved contact identity, objective, requester identity, session identifier, creation time, and a cryptographically random nonce. - Return only the opaque proposal identifier or nonce to the client. 3. **Bind approval to immutable parameters** - Require the confirmation operation to reference the pending proposal. - Dial using the destination and objective stored by the server rather than accepting replacement values from the confirmation request. - Reject approval if any call parameters differ from the previewed proposal. 4. **Require operator-controlled authorization** - Prefer an approval action performed through a trusted operator interface rather than allowing the same autonomous agent to preview and approve its own action. - Associate the approval with an authenticated operator identity. 5. **Expire and consume approvals** - Give proposals a short expiration period. - Make approval tokens single-use. - Delete or invalidate the proposal after approval, rejection, timeout, or call initiation. 6. **Preserve contact restrictions** - If policy requires calls to verified contacts, enforce that restriction regardless of the confirmation value. - Implement a separate, explicit operator override for unrecognized numbers. 7. **Add authorization and audit logging** - Record the proposal, operator approval identity, destination, objective hash, timestamps, and final result. - Avoid placing unnecessary call content or credentials in logs. 8. **Add regression tes ...[truncated 341 chars]
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (98)

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
# AGENT.md — Voice Assistant Persona & Instructions

This file defines how the voice assistant behaves on calls. Edit this to customize
personality, conversational flow, booking rules, and greetings.

Template variables (auto-replaced at runtime):
- `{{ASSISTANT_NAME}}` — assistant's name (env: `ASSISTANT_NAME`)
- `{{OPERATOR_NAME}}` — operator/boss name (env: `OPERATOR_NAME`)
- `{{ORG_NAME}}` — organization name (env: `ORG_NAME`)
- `{{DEFAULT_CALENDAR}}` — calendar name for bookings (env: `DEFAULT_CALENDAR`)
- `{{CALENDAR_REF}}` — resolves to "the {calendar} calendar" or "the calendar"

---

## Securi
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Exfiltration Commands

High
Category
Prompt Injection
Content
//   context.exec(cmd)           — run allowed local binaries only
  //   context.callLog.write(entry) — append to call log
  //   context.gateway.post(payload) — POST to OpenClaw gateway (if permitted)
  //   context.gateway.sendMessage(message) — send message to operator via OpenClaw
  //   context.call.id              — current call ID
  //   context.call.callerId        — caller's phone number
  //   context.call.transcript      — current transcript
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Self-Modification

High
Category
Rogue Agent
Content
- [ ] Environment detection (has server? use Asterisk)
- [ ] Automated Asterisk installation script
- [ ] SIP trunk configuration helper
- [ ] Update SKILL.md with Asterisk instructions

**Week 6: Testing & Release**
- [ ] End-to-end testing (inbound + outbound)
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Dynamic filesystem scanning and handler loading materially expand attack surface because any unauthorized or malicious skill directory/handler introduced on disk could be loaded into a privileged telephony environment. In a system with network, env, local file, and messaging permissions, plugin loading is dangerous unless tightly constrained and authenticated.

Ae1

High
Category
analysis-evasion
Content
Amber's skill system is designed to grow. Each skill is a self-contained directory with a `SKILL.md` (metadata + function schema) and a `handler.js`. You can:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **Dependency integrity:** runtime dependencies are pinned by `runtime/package-lock.json`; review dependency changes before publishing updates.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **Dependency integrity:** runtime dependencies are pinned by `runtime/package-lock.json`; review dependency changes before publishing updates.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- Review `runtime/package.json` dependencies before deployment in regulated environments.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
}

  // Generate
  head('Generating .env');
  await sleep(500);
  ok('.env written to /tmp/demo/.env');
Confidence
87% confidence
Finding
The script tells the user that a .env file containing configuration has been written to /tmp/demo/.env, a world-accessible temporary location on many systems. If real secrets are ever stored there, other local users, processes, backups, shell history workflows, or accidental commits could expose Twilio and OpenAI credentials.

Known Vulnerable Dependency: fast-uri==3.1.4 — 5 advisory(ies): CVE-2026-75931 (fast-uri vulnerable to host confusion via skipped IDN canonicalization on scheme); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +2 more

High
Category
Supply Chain
Confidence
85% confidence
Finding
The lockfile includes fast-uri 3.1.4, which is flagged for multiple URI parsing issues including host confusion and SSRF-related edge cases. In this skill’s context, URI handling matters because it integrates network-facing components and MCP/HTTP tooling, so a vulnerable URL parser in the dependency tree could enable request target confusion or SSRF if attacker-controlled URLs are ever processed.

Known Vulnerable Dependency: ip-address==10.2.0 — 3 advisory(ies): CVE-2026-54272 (ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR); CVE-2026-69198 (ip-address: a CIDR suffix on the parsed address suppresses special-use classific); CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco)

High
Category
Supply Chain
Confidence
88% confidence
Finding
The lockfile includes ip-address 10.2.0, which is reported to mis-handle special or malformed IP forms in ways that can bypass SSRF protections. That is particularly relevant here because the stack includes express-rate-limit and other network-facing services; incorrect IP classification can weaken trust boundaries, proxy checks, or SSRF defenses around telephony and MCP-exposed endpoints.

Credential Access

High
Category
Privilege Escalation
Content
// ── Helpers ──────────────────────────────────────────────────────────
const __dirname = dirname(fileURLToPath(import.meta.url));
const envPath   = resolve(__dirname, '.env');

let rl;
const ask = async (prompt, defaultVal) => {
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// ── Helpers ──────────────────────────────────────────────────────────
const __dirname = dirname(fileURLToPath(import.meta.url));
const envPath   = resolve(__dirname, '.env');

let rl;
const ask = async (prompt, defaultVal) => {
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

No suspicious patterns detected.