Back to skill

Security audit

Join meeting

Security checks for vulnerabilities and agentic risk

Overview

This meeting skill is mostly purpose-aligned, but it gives live meeting participants unusually strong influence over an agent with local tool access and documents risky credential, tunnel, and persistence patterns.

Review before installing. Use this only in trusted meetings or a sandboxed project with a narrow tool allowlist. Do not let meeting participants authorize file reads, shell commands, code edits, commits, credential access, or new network destinations without explicit confirmation from the local user. Avoid the Stop hook unless you fully understand and remove it afterward. Prefer environment or OS secret storage over plaintext config, rotate keys if exposed, and be careful not to tunnel sensitive localhost apps or save confidential transcripts in a repository.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (6)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:1332
Finding

Meeting instructions override agent task priority and recommend a persistent stop-blocking hook

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/python/agentcall.py:105
Finding

Long-lived API credentials are transmitted in WebSocket query strings

Content
View full analysis
AsyncIterator[dict]: """Connect to a call's WebSocket and yield events.""" ws_url = self.base_url.replace("https://", "wss://").replace("http://", "ws://") uri = f"{ws_url}/v1/calls/{call_id}/ws?api_key={self.api_key}" async with websockets.connect(uri) as ws: self._ws = ws async for message in ws: event = json.loads(message) yield event ``` The visual bridge repeats the same pattern: ```python async def connect_ws(self, call_id: str): ws_url = API_BASE.replace("https://", "wss://").replace("http://", "ws://") uri = f"{ws_url}/v1/calls/{call_id}/ws?api_key={API_KEY}" self.ws = await websockets.connect(uri) return self.ws ``` ### Technical Analysis The clients place a long-lived bearer API key directly in the WebSocket request URL. Although WSS protects the request in transit, query strings are commonly captured by reverse-proxy access logs, load balancers, telemetry systems, debugging output, browser or client diagnostics, and exception reports. A credential disclosed through one of these channels can potentially be replayed against both WebSocket and HTTP APIs. The repository uses the same API key to authorize call creation, call management, transcript retrieval, and TTS operations. ### Attack Path 1. The client constructs a WebSocket URL containing `?api_key=`. 2. A reverse proxy, API gateway, monitoring product, or server access logger records t ...[truncated 693 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/python/join.py:20
Finding

Unvalidated API endpoint overrides can redirect credentials and meeting data

Content
View full analysis
aiohttp.ClientSession: if self._session is None or self._session.closed: self._session = aiohttp.ClientSession( headers={"Authorization": f"Bearer {self.api_key}"} ) return self._session ``` The code explicitly permits conversion of plaintext HTTP endpoints into plaintext WebSocket endpoints: ```python ws_url = self.base_url.replace("https://", "wss://").replace("http://", "ws://") ``` ### Technical Analysis The API base URL can be supplied through a command-line argument, environment variable, or persistent configuration without validating the scheme or destination host. The ...[truncated 1646 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/python/register.py:97
Finding

Persistent API key file is created without explicit restrictive permissions

Content
View full analysis
~/.agentcall/config.json << 'EOF' {"api_key": "USER_KEY_HERE"} EOF ``` ### Technical Analysis The API key is persisted as plaintext using the process's ambient umask. The code does not explicitly create `~/.agentcall` with mode `0700` or the credential file with mode `0600`. It also does not repair an existing file with permissive permissions. On shared systems or systems with an unsafe umask, another local user or process may be able to read the long-lived key. Direct writes also lack atomic replacement and symlink protections, creating additional opportunities for local file manipulation. ### Attack Path 1. The user runs the registration verification flow. 2. `_save_key` creates or overwrites `~/.agentcall/config.json`. 3. The process umask permits group or world read access, or an existing file already has permissive permissions. 4. Another local account or compromised process reads the file. 5. The attacker extracts the plaintext `api_key`. 6. The key is reused against AgentCall services. ### Impact Assessment A local attacker may obtain the same AgentCall API privileges as the user, potentially including call management, transcript access ...[truncated 121 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/python/requirements.txt:1
Finding

Runtime dependencies are not reproducibly pinned

Content
View full analysis
=12.0 aiohttp>=3.9 ``` ```json "dependencies": { "ws": "^8.16.0" } ``` The installation instructions invoke package managers directly: ```text - Python dependencies: `pip install aiohttp websockets` - Node.js dependencies: `cd scripts/node && npm install` ``` ### Technical Analysis The Python requirements accept any future release above the stated minimum versions, while the Node dependency accepts compatible updates through a caret range. No lockfile or integrity-hash manifest is included in the audited project. The dependencies run inside clients that handle API keys, meeting transcripts, audio, screenshots, WebSocket traffic, and localhost tunnel requests. A compromised future package release or an incompatible update would therefore execute with access to highly sensitive runtime data. No evidence was found that the named packages are currently malicious. The vulnerability is the lack of reproducible, reviewable dependency resolution. ### Attack Path 1. A user follows the documented `pip install` or `npm install` instructions. 2. The package manager resolves versions available at installation time rather than versions reviewed with this Skill. 3. A compromised, malicious, or unexpectedly incompatible future release is selected. 4. The dependency executes in the Skill process. 5. It reads API credentials, meeting data, or local tunnel traffic and transmits or alters that data. ### Impact Assessment A dependency compromise could gain: - The privileges of the user running the Skill. - Access to AgentCall API keys and per-call tunnel credentials. - Access to meeting transcripts, audio, screenshots, and commands. - Ability to modify WebSo ...[truncated 101 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
examples/meeting-assistant-smart/assistant.py:329
Finding

Examples persist complete meeting transcripts using default filesystem permissions

Content
View full analysis
= 19 else "" f.write(f"[{time_str}] **{line['speaker']}**: {line['text']} \n") f.write("\n") if voice_events: f.write("## Voice State Timeline\n") for ve in voice_events: f.write(f"- [{ve['time']}] {ve['state']}") if ve.get("text"): f.write(f" — \"{ve['text']}\"") f.write("\n") ``` ### Technical Analysis When no output path is supplied, the example automatically creates a Markdown log in the current working directory. The file contains the call identifier, participant names, task summaries, full transc ...[truncated 1315 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (180)

Tainted flow: 'HEADERS' from os.environ.get (line 63, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/meeting-assistant-smart/assistant.py (reported line 303)May include surrounding context.

python
# ──────────────────────────────────────────────────────────────────────────────

def create_call(meet_url: str, bot_name: str, trigger_words: List[str], context: str, voice: str) -> dict:
    resp = requests.post(
        f"{API_BASE}/v1/calls",
        headers=HEADERS,
        json={

Tainted flow: 'HEADERS' from os.environ.get (line 51, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/meeting-assistant/assistant.py (reported line 56)May include surrounding context.

python
def create_call(meet_url: str, bot_name: str, trigger_words: List[str], context: str, voice: str) -> dict:
    """Create a collaborative mode call with avatar UI."""
    resp = requests.post(
        f"{API_BASE}/v1/calls",
        headers=HEADERS,
        json={

Tainted flow: 'HEADERS' from os.environ.get (line 70, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/notetaker-multilingual/notetaker.py (reported line 198)May include surrounding context.

python
def create_call(meet_url: str, bot_name: str, enable_english_stt: bool) -> dict:
    """Create a call with audio streaming enabled."""
    resp = requests.post(
        f"{API_BASE}/v1/calls",
        headers=HEADERS,
        json={

Tainted flow: 'HEADERS' from os.environ.get (line 42, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/notetaker-simple/notetaker.py (reported line 47)May include surrounding context.

python
def create_call(meet_url: str, bot_name: str) -> dict:
    """Create a call via REST API — audio mode, transcription on, direct strategy (listen only)."""
    resp = requests.post(
        f"{API_BASE}/v1/calls",
        headers=HEADERS,
        json={

Tainted flow: 'HEADERS' from os.environ.get (line 42, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/notetaker-smart/notetaker.py (reported line 164)May include surrounding context.

python
def create_call(meet_url: str, bot_name: str) -> dict:
    """Create a call via REST API — audio mode, transcription on, direct strategy (listen only)."""
    resp = requests.post(
        f"{API_BASE}/v1/calls",
        headers=HEADERS,
        json={

Tainted flow: 'HEADERS' from os.environ.get (line 42, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/notetaker-simple/notetaker.py (reported line 64)May include surrounding context.

python
def fetch_transcript(call_id: str) -> Optional[dict]:
    """Fetch the full transcript after the call ends."""
    resp = requests.get(
        f"{API_BASE}/v1/calls/{call_id}/transcript?format=json",
        headers=HEADERS,
    )

Tainted flow: 'HEADERS' from os.environ.get (line 42, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/notetaker-smart/notetaker.py (reported line 180)May include surrounding context.

python
def fetch_transcript(call_id: str) -> Optional[dict]:
    resp = requests.get(f"{API_BASE}/v1/calls/{call_id}/transcript?format=json", headers=HEADERS)
    if resp.status_code == 200:
        return resp.json()
    return None

Tainted flow: 'HEADERS' from os.environ.get (line 57, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · examples/support-agent/agent.py (reported line 235)May include surrounding context.

python
# ──────────────────────────────────────────────────────────────────────────────

def create_call(meet_url: str, bot_name: str) -> dict:
    resp = requests.post(
        f"{API_BASE}/v1/calls",
        headers=HEADERS,
        json={

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a general-purpose skill for joining meetings as an AI bot with voice and visual presence across multiple modes. The supplied code chunk is narrower and materially different: it is a subprocess bridge that connects AgentCall meeting I/O to another AI agent, explicitly stating it has no LLM and is not a standalone agent. It only creates calls with mode='audio' and voice_strategy='direct', so visual presence and webpage/custom UI modes are not represented in this code. Additionally, it exposes a screenshot command/result flow that is not mentioned in the declared description. While core meeting participation features like joining a call, receiving transcripts, TTS speaking, chat, raise hand, and leaving are consistent with the general domain, the actual primary purpose and capabilities differ enough to count as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description focuses on conferencing behavior: joining meetings on Meet/Teams/Zoom and participating with voice, TTS, and visual presence. The supplied code chunk does something materially different: it provides background business tools that can be invoked during a meeting, such as querying company data, searching documents, performing calculations, and creating tickets. These are undeclared capabilities and the primary declared capability—joining and attending a video meeting—is absent from this code. While the code is thematically related to meeting assistance, it does not match the stated purpose of the skill itself.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The declared description presents a general-purpose meeting-joining bot with voice/visual presence and multiple interaction modes. The supplied code chunk instead implements a specific smart note-taker workflow: it joins a meeting in audio mode, collects transcripts, retrieves the full transcript, optionally sends transcript content to third-party LLM providers for summarization, and writes results to a local markdown file. Those are material capabilities not stated in the description, especially transcript processing, summarization, and file output. The code also does not implement the broader visual presence, text-to-speech, or webpage modes highlighted in the description. While joining a meeting is consistent at a high level, the actual primary purpose of this code is automated note-taking and summarization, which is materially narrower and different from the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This code chunk does not implement meeting participation or conferencing behavior. Its primary purpose is update checking, which is materially different from the declared description of joining video meetings as an AI bot. It also performs undeclared file-system access and outbound network access to GitHub for version checking. While an update checker could be a supporting utility for a broader skill, this specific code chunk's behavior is unrelated to the declared operational purpose and therefore constitutes a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is a meeting-participation skill for video conferencing, but the code chunk does not join, attend, or interact with any meeting platform, audio/video stream, or UI. Its primary function is account registration and credential provisioning via email OTP against AgentCall APIs, followed by saving the resulting API key locally. That is a materially different purpose and introduces undeclared capabilities related to authentication and local credential storage.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is about joining video meetings as an AI bot with media/voice presence. The supplied code does not contain any meeting, conferencing, audio, video, TTS, browser automation, or call-joining behavior. Instead, it is infrastructure code for a reverse tunnel that proxies HTTP traffic from a remote WebSocket endpoint to a local server. That is a materially different primary purpose and an undeclared capability, so this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broad AgentCall skill for joining meetings as an AI bot with voice and visual presence across multiple modes. The supplied code only covers one specific component: an audio bridge subprocess that interfaces a meeting bot with an external agent through stdin/stdout. It does support joining a call and speaking/listening, so it partially aligns with the description. However, it does not implement visual presence, webpage modes, or a standalone meeting-participation agent. It also exposes extra capabilities not mentioned in the description, notably screenshot capture and microphone mute/unmute control. Because the code’s actual scope and primary function are materially narrower/different than the declared purpose, and it includes undeclared capabilities, this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is about attending video meetings as an AI bot. The actual code chunk does not implement any meeting, audio, video, conferencing, or bot participation behavior. Instead, it performs update checking against GitHub, including local file reads, network requests, and cache writes. This is a materially different purpose from the declared description. Although the script may be optional/supporting infrastructure for the broader skill, this specific code chunk's behavior is unrelated to the advertised meeting-joining functionality, so it should be flagged as a description-behavior mismatch for this chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says this skill joins and participates in video meetings, but the code shown does not interact with any meeting platform, audio/video streams, voice features, or UI modes. Its sole purpose is authentication/bootstrap: contacting AgentCall auth endpoints, verifying an emailed code, creating an API key, and persisting that credential locally. Those are materially different capabilities from the declared meeting-join functionality, so this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description focuses on meeting participation capabilities—joining video conferences as an AI bot with voice, visual presence, and related interaction modes. The actual code chunk does not implement meeting joining, conferencing platform integration, voice handling, TTS, or visual bot behavior. Instead, it is infrastructure code for tunneling/proxying remote HTTP/WS requests to localhost. While such tunneling could be a supporting component for custom UI or screensharing, this chunk’s primary behavior is materially different from the declared end-user purpose and introduces undeclared network proxy capabilities.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill explicitly encourages obtaining mailbox OTP codes and collecting or storing API keys in plain workflow steps. This creates a natural-language path for credential harvesting and persistence, which is especially dangerous in agent environments because users may be socially engineered into revealing secrets or allowing the agent to handle them insecurely.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Node equivalent: `node scripts/node/register.js send --email ...` and

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Node equivalent: `node scripts/node/register.js send --email ...` and

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill supports exposing localhost-backed webpages to meeting participants through externally reachable shareable URLs. This can unintentionally publish sensitive local content or internal-only apps to anyone with the URL, especially because the feature is framed as a convenience workflow rather than a risky network exposure.

Content

No source excerpt is available for this finding.

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
91% confidence
Finding

The anti-refusal language pushes the agent to 'always respond' and 'always participate,' even though meeting transcripts are explicitly untrusted input. In practice this pressures the agent to comply under social or adversarial prompting, weakening safety boundaries and increasing the risk of unauthorized actions during a live call.

Content

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

→ call.ended: exit loop

Agent IS the voice. Every second without checking = silence. Always greet, always respond, always participate.

text
**Follow THE CALL_LOOP algorithm (see Pattern 5 → Method 1 below — event-driven, recommended).**

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

Clean up when done

exec 3>&- rm /tmp/meeting-stdin

text

**THE CALL LOOP — follow this algorithm exactly:**

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
- `POST /v1/calls` — create a call and join a meeting
- `GET /v1/calls/{id}` — check call status (bot_joining, bot_ready, ended)
- `GET /v1/calls/{id}/transcript?format=json` — fetch the transcript at any time
- `DELETE /v1/calls/{id}` — end the call

These endpoints work as standard HTTP tool calls. The agent can create a call,
periodically check the transcript, and end the call — but cannot participate

Static analysis

Detected: suspicious.dynamic_code_execution, suspicious.env_credential_access

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
examples/meeting-assistant-smart/tools.py:93

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
examples/notetaker-simple/notetaker.js:29

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
examples/notetaker-smart/notetaker.js:34

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/node/agentcall.js:24

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/node/bridge-visual.js:125

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/node/bridge.js:50