Back to skill

Security audit

Meeting Summary

Security checks for vulnerabilities and agentic risk

Overview

This meeting-summary skill appears purpose-aligned, but it processes highly sensitive meeting audio, transcripts, API keys, and voiceprints with several under-scoped safeguards that users should review before installing.

Review this before installing if your meetings include confidential, regulated, or personal information. Use only with meetings whose participants consent to cloud transcription/summarization and voiceprint matching. Do not set MEETING_SUMMARY_LLM_URL to an untrusted endpoint, protect or avoid plaintext API key files, avoid enrolling voiceprints without a clear retention/deletion policy, and treat this version as needing fixes for endpoint validation, voiceprint filename sanitization, and sensitive cache permissions.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
scripts/meeting-summarize.py:56
Finding

Configurable LLM Endpoint Can Receive StepFun Credentials and Confidential Meeting Transcripts

Content
View full analysis
Dict[str, object]: api_key = load_api_key() if not api_key: raise RuntimeError("StepFun API key is not configured for LLM enrichment") payload = { "model": STEP_LLM_MODEL, "temperature": 0.2, "response_format": {"type": response_hint}, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], } req = urllib.request.Request( STEP_CHAT_COMPLETIONS_URL, data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "Accept": "application/json", }, method="POST", ) try: with urllib.request.urlopen(req, timeout=180) as resp: raw = resp.read().decode("utf-8", errors="replace") ``` ### Technical Analysis The destination of an authenticated LLM request is taken directly from the `MEETING_SUMMARY_LLM_URL` environment variable. The code does not validate the scheme, hostname, port, or origin before attaching a StepFun bearer credential. The request body includes user-derived meeting information. Depending on the operation, this includes transcript excerpts, participant candidates, confidence flags, and potentially information derived from historical meeting minutes. Consequently, control of the environment variable provides a ...[truncated 1385 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/voiceprint-manager.py:177
Finding

Path Traversal Through Voiceprint Names Allows Filesystem Writes and Deletions Outside the Voiceprint Store

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/meeting-summarize.py:1188
Finding

Sensitive Meeting Caches and Biometric Voice Embeddings Are Stored Without Explicit Access Controls

Content
View full analysis
str: os.makedirs(CACHE_DIR, exist_ok=True) parts = [compute_audio_fingerprint(audio_path), stage] if extra_parts: parts.extend(str(part) for part in extra_parts if str(part)) filename = "--".join(parts) + ".json" return os.path.join(CACHE_DIR, filename) def load_json_cache(path: str) -> Optional[Dict[str, object]]: if not os.path.exists(path): return None with open(path, "r", encoding="utf-8") as handle: return json.load(handle) def save_json_cache(path: str, payload: Dict[str, object]) -> None: os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, "w", encoding="utf-8") as handle: json.dump(payload, handle, ensure_ascii=False, indent=2) ``` ```python def ensure_dir(): os.makedirs(VOICEPRINT_DIR, exist_ok=True) def save_voiceprint(name, embedding): ensure_dir() path = os.path.join(VOICEPRINT_DIR, f"{name}.json") data = { "name": name, "embedding": embedding.tolist(), "dim": len(embedding) } with open(path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) return path ``` ### Technical Analysis The Skill persistently caches ASR and diarization results and stores speaker embeddings under the OpenClaw workspace. Files and directories are created using process-default permissions. There is no explicit `0700` directory mode, `0600` file mode, encryption, retention limit, or access-control verification. ASR caches can contain full meeting transcripts. Voice embeddings are persistent biometric identifiers associated with participant names. Alt ...[truncated 1395 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
references/setup-guide.md:29
Finding

Unpinned Python Dependencies and Unverified Model Downloads Create Supply-Chain Risk

Content
View full analysis
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (38)

Tainted flow: 'req' from os.environ.get (line 1063, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The code builds an authenticated HTTP request to a URL that can be overridden by MEETING_SUMMARY_LLM_URL, then sends sensitive meeting transcript content and the API bearer token to that destination. An attacker who controls the environment can redirect requests to an arbitrary server, exfiltrating confidential meeting data and credentials.

Content

Scanner excerpt · scripts/meeting-summarize.py (reported line 1074)May include surrounding context.

python
method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=180) as resp:
            raw = resp.read().decode("utf-8", errors="replace")
    except urllib.error.HTTPError as exc:
        err_body = exc.read().decode("utf-8", errors="replace")

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明描述的是一个完整的“会议录音→结构化纪要”流水线,包含转写、说话人分割、声纹实名、纪要生成和长录音处理等多项能力。但本代码块的实际功能仅限于 ASR 转写客户端:上传音频到 Step API、接收转写结果、可选 SSE 流式输出,并保存文本/JSON。代码中没有 pyannote、说话人标签、声纹识别、实名映射、LLM 调用、摘要/纪要结构化生成,也没有对长录音进行切块或增量合并处理。因此,该代码块只覆盖了声明中的“Step ASR 转写”一部分,无法准确代表整个声明用途,属于明显描述与行为不一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description presents a broad end-to-end meeting processing skill, but this code chunk only implements speaker embedding extraction and voiceprint management/identification. Its diarize command merely labels provided time segments (or simple energy-based VAD segments) with enrolled speaker names; it is not pyannote diarization and does not itself transcribe speech. There is no code for generating structured meeting notes, invoking an LLM, or chunking long recordings for incremental processing. Additionally, the code exposes extra management operations (enroll/list/delete) not reflected in the declared purpose. While voiceprint real-name matching is consistent with part of the description, the overall behavior is materially narrower and different from the declared end-to-end meeting-minutes functionality.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill handles meeting recordings and appears to use external services for transcription and summarization, but it does not clearly warn users that audio and derived content may leave the local environment. Meeting audio often contains confidential business, legal, or personal information, so absent disclosure undermines informed consent and increases privacy and compliance risk.

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 80)May include surrounding context.

md
python3 scripts/meeting-summarize.py \

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill includes voiceprint enrollment, identification, listing, and deletion, which means it collects and stores biometric identifiers, but the description lacks an explicit biometric-data warning. Voiceprints are highly sensitive personal data; collecting them without clear notice, consent, storage policy, and deletion guidance creates significant privacy, legal, and abuse risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README instructs users to send meeting recordings to an external ASR provider but does not clearly warn that audio content may leave the local environment and may contain sensitive business or personal information. Meeting audio often includes confidential discussions, PII, or regulated data, so lack of an explicit transmission/privacy notice can lead to unintentional disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The README promotes voiceprint enrollment and speaker identification without clearly warning that voiceprints are biometric identifiers and require heightened consent, retention, and access controls. Collecting and matching biometric data without explicit privacy guidance can create serious legal, privacy, and misuse risks, especially in workplace recordings.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill instructs use of shell commands, file reads/writes, environment-variable access, and networked API use, but does not declare any explicit tool scope or permission boundaries. This increases the chance of over-privileged execution and makes it harder for hosts and users to understand or constrain what the skill is allowed to do.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are broad enough to activate on common requests like summarizing audio or identifying who is speaking, which can cause the skill to run in contexts the user did not intend. In this skill, accidental activation is more serious because execution may process local audio, access stored tokens, and send content to external services.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

The skill is configured to send content to an external API endpoint, which is expected for cloud summarization, but it is still a real data-exposure concern because the content includes meeting audio-derived material and possibly sensitive transcripts. In this context, external transmission is more dangerous than usual because meetings can contain confidential discussions and participant identity data.

Content

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

md
| `HF_TOKEN` | 空 | Hugging Face token(pyannote gated model 需要) |
| `STEPFUN_API_KEY` | 从 `~/.stepfun_api_key` 读取 | StepFun API Key |
| `MEETING_SUMMARY_LLM_MODEL` | `step-3.5-flash` | LLM 模型名 |
| `MEETING_SUMMARY_LLM_URL` | `https://api.stepfun.com/v1/chat/completions` | LLM API 地址 |
| `MEETING_SUMMARY_WORKSPACE` | `~/.openclaw/workspace` | 工作区根目录 |

---

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/setup-guide.md (reported line 23)May include surrounding context.

Or download static binary from https://evermeet.cx/ffmpeg/ (macOS)

Linux (Ubuntu/Debian)

sudo apt install ffmpeg

text

Verify: `ffmpeg -version`

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/setup-guide.md (reported line 52)May include surrounding context.

Or download static binary from https://evermeet.cx/ffmpeg/ (macOS)

Linux (Ubuntu/Debian)

sudo apt install ffmpeg

text

Verify: `ffmpeg -version`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The guide explicitly instructs users to use external StepFun ASR and LLM services for meeting audio and transcripts, but it does not clearly warn that potentially sensitive meeting content will be transmitted to a third-party provider. In a meeting-summary skill, this is significant because recordings may contain confidential business, personal, or regulated data, and users need informed consent before sending it off-device.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The guide recommends storing a long-lived API key in a plaintext file under the user's home directory for repeated use. While chmod 600 helps, persistent plaintext credential storage still increases the blast radius of local compromise, shell history mistakes, backup leakage, or accidental disclosure on shared systems.

Content

Scanner excerpt · references/setup-guide.md (reported line 68)May include surrounding context.

md
1. Go to **https://platform.stepfun.com/interface-key**
2. Sign up / Log in
3. Navigate to **API Keys** → **Create New Key**
4. Copy the key

### Save the Key

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 203)May include surrounding context.

bash
echo "your-api-key-here" > ~/.stepfun_api_key
chmod 600 ~/.stepfun_api_key

The scripts look for the key in this order:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/setup-guide.md (reported line 75)May include surrounding context.

bash
echo "your-api-key-here" > ~/.stepfun_api_key
chmod 600 ~/.stepfun_api_key

The scripts look for the key in this order:

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The documented default LLM endpoint points to an external API, confirming that meeting-derived content can be transmitted off-host. In the context of meeting summaries, external transmission is more sensitive than usual because source audio and generated summaries can contain confidential information, yet the guide does not pair this with a strong disclosure or guidance on safe use.

Content

Scanner excerpt · references/setup-guide.md (reported line 192)May include surrounding context.

md
| Variable | Default | Purpose |
|----------|---------|---------|
| `MEETING_SUMMARY_PYANNOTE_PYTHON` | (none) | Path to pyannote venv python binary |
| `MEETING_SUMMARY_LLM_URL` | `https://api.stepfun.com/v1/chat/completions` | LLM API endpoint |
| `MEETING_SUMMARY_LLM_MODEL` | `step-3.5-flash` | LLM model for speaker estimation & summary |
| `STEPFUN_API_KEY` | (reads from `~/.stepfun_api_key`) | StepFun API key |
| `PYANNOTE_PIPELINE_PATH` | `~/.openclaw/workspace/models/pyannote-community-1` | Local pyannote model path |

Session Persistence

Medium
Category
Rogue Agent
Confidence
82% confidence
Finding

The troubleshooting section reinforces persistent storage of the API key in a plaintext file, normalizing a weaker secret-handling pattern. In a skill that interacts with paid external APIs and sensitive meeting data, compromised credentials could enable unauthorized API use and indirect data exposure.

Content

Scanner excerpt · references/setup-guide.md (reported line 237)May include surrounding context.

md
## Troubleshooting

### "No StepFun API key found"
→ Create `~/.stepfun_api_key` with your key, or set `STEPFUN_API_KEY` env var.

### "Audio preprocessing failed"
→ Ensure ffmpeg is installed and in PATH: `which ffmpeg`

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

python
MIN_CHUNK_SPEECH_MS = 12 * 1000
MONOLOGUE_MAX_REGIONS = 3
MONOLOGUE_DOMINANCE_THRESHOLD = 0.78
STEP_CHAT_COMPLETIONS_URL = os.environ.get("MEETING_SUMMARY_LLM_URL", "https://api.stepfun.com/v1/chat/completions")
STEP_LLM_MODEL = os.environ.get("MEETING_SUMMARY_LLM_MODEL", "step-3.5-flash")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/meeting-summarize.py (reported line 61)May include surrounding context.

python
def run_command(cmd: List[str], timeout: int = 300) -> subprocess.CompletedProcess:
    return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)


def preprocess_audio(audio_path: str) -> Tuple[str, Dict[str, object]]:

Tainted flow: 'cmd' from os.environ.get (line 130, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
83% confidence
Finding

The subprocess sink is reachable from an environment-controlled executable path via MEETING_SUMMARY_PYANNOTE_PYTHON, which is inserted as argv[0] and later executed. If an attacker can influence the runtime environment, they can cause arbitrary local code execution under the user's privileges by pointing this variable to a malicious binary or script.

Content

Scanner excerpt · scripts/meeting-summarize.py (reported line 61)May include surrounding context.

python
def run_command(cmd: List[str], timeout: int = 300) -> subprocess.CompletedProcess:
    return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)


def preprocess_audio(audio_path: str) -> Tuple[str, Dict[str, object]]:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The ASR path invokes an external transcription component for meeting audio, and the surrounding skill description indicates Step ASR is a preferred path. Because meeting audio is highly sensitive and may include voices and proprietary discussions, sending it off-box without clear disclosure or consent is a real privacy and data-handling vulnerability in this context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The transcription function defaults language to zh, and the summarization prompts and markdown output are hard-coded in Chinese, making Chinese the effective default behavior. This is a language policy concern because users are placed into a specific locale by default rather than being asked to choose or clearly opt in.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill's stated purpose is meeting recording to structured minutes, including LLM minute generation, so networked summarization is in scope. However, this implementation also searches general environment variables and credential files in the user's home directory to obtain API keys, which is a broader sensitive-data access capability than the manifest describes.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.