Back to skill

Security audit

meeting record analysis

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says: it turns meeting audio into minutes using external ASR, LLM, and optional TTS services, with sensitive-data handling risks users should understand.

Install only if you are comfortable sending meeting recordings and derived text to the configured ASR, LLM, and TTS providers. Use approved enterprise endpoints and API keys, avoid sensitive meetings unless provider retention/compliance terms are acceptable, and review generated minutes before relying on decisions or action items.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_meeting_minutes.py:176
Finding
Indirect Prompt Injection Through Untrusted Meeting Transcripts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_meeting_minutes.py:176-199` **Additional Location**: `scripts/run_meeting_minutes.py:150-172` **Vulnerability Type**: Indirect prompt injection and insufficient output validation **Risk Level**: Medium ### Complete Code Snippet ```python def summarize_meeting(transcript: str) -> dict[str, Any]: prompt = f"""You are an AI assistant that generates meeting minutes. Analyze the following meeting transcript and return JSON with these fields: - topic - discussion_points - decisions - action_items - voice_summary_text Rules: - do not fabricate missing facts - discussion_points should be concise - decisions should only include confirmed conclusions - action_items should include owner if mentioned Transcript: {transcript} """ client = build_client() response = client.chat.completions.create( model=LLM_MODEL, temperature=0.3, messages=[ {"role": "system", "content": "Return valid JSON only."}, {"role": "user", "content": prompt}, ], ) return extract_json(extract_message_content(response)) ``` The same unsafe interpolation pattern is used during transcript cleaning: ```python def clean_transcript_with_llm(transcript: str) -> str: prompt = f"""You are an assistant that cleans meeting transcripts. Clean the transcript below: - remove filler words - remove repeated phrases - improve readability - preserve facts, names, numbers, decisions, and action items Transcript: {transcript} Return only the cleaned transcript text. """ client = build_client() response = client.chat.completions.create( model=LLM_MODEL, temperature=0.2, messages=[ {"role": "system", "content": "Return only cleaned transcript text."}, {"role": "user", "content": prompt}, ], ) return extract_message_content(response) ``` ### Technical Analysis The transcript originates from us ...[truncated 2150 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat all transcript text as untrusted data and explicitly state in the system instruction that commands, policies, or requests appearing inside the transcript must never be followed. 2. Place transcript data inside clearly identified boundaries or pass it through a structured input field rather than concatenating it with task instructions. 3. Use provider-supported structured output or JSON Schema enforcement for the summary response. 4. Validate the parsed object before use: - Require all expected fields. - Require `topic` and `voice_summary_text` to be strings. - Require `discussion_points`, `decisions`, and `action_items` to be arrays of strings. - Reject unexpected nesting, excessive lengths, and unknown fields where appropriate. 5. Add post-generation grounding checks for decisions and action items, especially before using them in automated workflows. 6. Do not silently accept suspicious or malformed model output. Reject it or retry with a constrained prompt. 7. Add adversarial tests containing spoken prompt-injection phrases and verify that they are represented only as meeting content, not followed as instructions. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unbounded Third-Party Dependency Versions<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-3` **Vulnerability Type**: Unpinned dependencies and non-reproducible dependency resolution **Risk Level**: Low ### Complete Code Snippet ```text openai>=1.30.0 requests>=2.31.0 python-dotenv>=1.0.0 ``` ### Technical Analysis Each dependency is specified only with a minimum version. A future installation may therefore resolve to any later release, including versions that have not been reviewed or tested with this Skill. No lock file or package hashes are present to verify the exact artifacts installed. The package names are established packages, and the reviewed project contains no evidence of typosquatting, dependency confusion, or an intentionally malicious package. The risk arises from unrestricted future resolution and lack of artifact integrity controls rather than a currently confirmed malicious dependency. ### Attack Path 1. A new dependency release introduces a malicious change, supply-chain compromise, or security regression. 2. A user runs `pip install -r requirements.txt`. 3. The package resolver selects the affected newer release because it satisfies the lower-bound constraint. 4. Package installation or runtime behavior executes within the privileges of the user running the Skill. 5. The compromised dependency may access the same files, environment variables, API credentials, and network resources available to the process. ### Impact Assessment If an allowed future dependency version is compromised, code from that dependency could execute with the privileges of the Skill process. This could expose meeting audio, transcripts, API credentials, generated outputs, and other resources accessible to that user. The current repository does not demonstrate an active compromise. The practical impact depends on a malicious or vulnerable future release being selected during installation. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin each dependency to a reviewed exact version rather than using only lower bounds. 2. Generate and commit a reproducible lock file for the supported Python environment. 3. Require package hashes, such as through `pip-compile --generate-hashes` and `pip install --require-hashes`. 4. Perform dependency updates through a controlled review process with automated vulnerability scanning and regression testing. 5. Prefer trusted package indexes and prevent fallback to unapproved indexes in deployment configuration. 6. Periodically update pins after reviewing security advisories so that reproducibility does not prevent timely security patching. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (23)

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

Critical
Category
Data Flow
Content
data["language"] = language
    with audio_file.open("rb") as handle:
        files = {"file": (audio_file.name, handle)}
        response = requests.post(ASR_URL, headers=headers, data=data, files=files, timeout=ASR_TIMEOUT)
    if response.status_code != 200:
        raise RuntimeError("Speech recognition failed")
    payload = response.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
"voice_setting": {"voice_id": TTS_VOICE_ID},
        "audio_setting": {"format": "mp3", "sample_rate": 32000},
    }
    response = requests.post(TTS_URL, headers=headers, json=payload, timeout=TTS_TIMEOUT)
    response.raise_for_status()
    result = response.json()
    if result.get("base_resp", {}).get("status_code") != 0:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Credential Access

High
Category
Privilege Escalation
Content
def load_env() -> None:
    if load_dotenv is None:
        return
    for path in (SKILL_DIR / ".env", Path.cwd() / ".env"):
        if path.exists():
            load_dotenv(path)
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill documentation indicates capabilities that access environment variables, write local files, and call external network services, but it does not declare any explicit tool scope or permission boundaries. This can lead to over-broad execution in agent environments, making it harder for users and platforms to understand or constrain what the skill is allowed to do.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The file declares `language: zh` as the default, which imposes a specific locale choice by default. While the input field exists, the description does not present the locale behavior as a user choice or justify why Chinese should be the enforced default for users who do not explicitly opt in.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This skill sends meeting audio and derived transcripts to third-party ASR, LLM, and optional TTS services, but the description does not warn users that potentially sensitive meeting content leaves the local environment. In a meeting-minutes context, recordings often contain confidential business information, personal data, or internal decisions, so undisclosed external transmission creates meaningful privacy and compliance risk.

External Transmission

Medium
Category
Data Exfiltration
Content
LLM_API_KEY = os.environ.get("MEETING_LLM_API_KEY", os.environ.get("IME_MODEL_API_KEY", ""))
    LLM_TIMEOUT = float(os.environ.get("MEETING_LLM_TIMEOUT", "60"))

    ASR_URL = os.environ.get("MEETING_ASR_URL", "https://api.senseaudio.cn/v1/audio/transcriptions")
    ASR_MODEL = os.environ.get("MEETING_ASR_MODEL", "sense-asr-pro")
    ASR_API_KEY = os.environ.get("MEETING_ASR_API_KEY", os.environ.get("SENSEAUDIO_API_KEY", ""))
    ASR_RESPONSE_FORMAT = os.environ.get("MEETING_ASR_RESPONSE_FORMAT", "verbose_json")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
LLM_API_KEY = os.environ.get("MEETING_LLM_API_KEY", os.environ.get("IME_MODEL_API_KEY", ""))
    LLM_TIMEOUT = float(os.environ.get("MEETING_LLM_TIMEOUT", "60"))

    ASR_URL = os.environ.get("MEETING_ASR_URL", "https://api.senseaudio.cn/v1/audio/transcriptions")
    ASR_MODEL = os.environ.get("MEETING_ASR_MODEL", "sense-asr-pro")
    ASR_API_KEY = os.environ.get("MEETING_ASR_API_KEY", os.environ.get("SENSEAUDIO_API_KEY", ""))
    ASR_RESPONSE_FORMAT = os.environ.get("MEETING_ASR_RESPONSE_FORMAT", "verbose_json")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The code uploads the full meeting audio to an external ASR service without any user-facing consent, warning, or trust boundary notice. Because meeting recordings often contain confidential business discussions and personal data, undisclosed third-party transmission is a meaningful privacy and compliance risk in this skill context.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The cleaned transcript is sent to an external LLM for post-processing without notifying the user. This exposes potentially sensitive meeting content to an additional third party beyond the ASR provider, increasing confidentiality, regulatory, and vendor-risk concerns.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The transcript is sent again to an external LLM for summarization without a user-facing warning. In a meeting-minutes assistant, this is especially sensitive because the content may include trade secrets, HR matters, financial details, or personal information, making undisclosed external processing more dangerous.

External Transmission

Medium
Category
Data Exfiltration
Content
"voice_setting": {"voice_id": TTS_VOICE_ID},
        "audio_setting": {"format": "mp3", "sample_rate": 32000},
    }
    response = requests.post(TTS_URL, headers=headers, json=payload, timeout=TTS_TIMEOUT)
    response.raise_for_status()
    result = response.json()
    if result.get("base_resp", {}).get("status_code") != 0:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The CLI sets the default language to "zh", causing speech recognition to assume a specific language unless the user overrides it. This is a locale policy concern because the tool imposes a language default rather than prompting for or detecting user preference.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The skill states that it saves structured meeting results to a local JSON file but does not clearly warn users about this persistence behavior. Meeting minutes may contain sensitive transcript excerpts, decisions, and action items, so silent local storage can expose data to other local users, backup systems, or later unintended access.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The manifest names the skill entirely in Chinese ("会议录音转纪要") with no indication that users can choose another language or locale. This can violate language/locale policy if the organization requires user choice rather than silently forcing a single language presentation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
openai>=1.30.0
requests>=2.31.0
python-dotenv>=1.0.0
Confidence
93% confidence
Finding
The dependency is specified with a lower bound only (`openai>=1.30.0`), which makes builds non-reproducible and allows future package releases to be installed without review. While this is primarily a supply-chain hygiene issue rather than an immediately exploitable flaw by itself, it can expose the skill to breaking changes or newly introduced vulnerabilities in later versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
openai>=1.30.0
requests>=2.31.0
python-dotenv>=1.0.0
Confidence
97% confidence
Finding
`requests>=2.31.0` is unpinned, so deployments may resolve to different versions over time, including versions later found vulnerable or behaviorally incompatible. In a skill that likely performs network calls for transcription or summarization workflows, dependency drift increases supply-chain risk and makes it harder to verify whether known fixes are actually present.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The manifest does not pin `requests`, and that package has multiple known advisories across versions, so the actual installed dependency may be vulnerable without any way to verify from this file alone. Because this skill likely sends data to remote services, a vulnerable HTTP client could increase risks such as credential leakage, TLS/verification issues, or other request-handling weaknesses depending on the resolved version.

Unpinned Dependencies

Low
Category
Supply Chain
Content
openai>=1.30.0
requests>=2.31.0
python-dotenv>=1.0.0
Confidence
95% confidence
Finding
`python-dotenv>=1.0.0` is not pinned, so the installed version may vary by environment and time, preventing reliable assurance about security posture. This matters because dotenv libraries influence secret loading and file handling behavior, so unnoticed version changes can affect both security and runtime behavior.

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
82% confidence
Finding
`python-dotenv` has known advisories in some versions, but the unpinned requirement prevents determining whether a safe or affected release will be installed. In this skill context, dotenv is likely used for configuration and API secrets, so an unsafe version could contribute to file-handling or environment-management issues, though the manifest alone does not show active exploitation.

Context-Inappropriate Capability

Low
Confidence
78% confidence
Finding
The skill's purpose is audio transcription, summarization, and optional TTS, but the code also scans for and loads `.env` files from the skill directory and current working directory. Reading local secret-bearing config files is an operational capability beyond the user-facing purpose described in the manifest.

Missing User Warnings

Low
Confidence
90% confidence
Finding
When voice summary is requested, summary text is sent to an external TTS provider without clearly informing the user. Although less sensitive than full audio or transcript, the summary can still contain confidential decisions, names, and action items, so undisclosed transmission remains a privacy issue.

Description-Behavior Mismatch

Low
Confidence
89% confidence
Finding
The script returns and persists the full cleaned transcript in addition to structured minutes, which exceeds the described default output and may expose sensitive meeting content beyond what users expect. In a meeting-minutes context, retaining and printing more raw content materially increases confidentiality risk and downstream leakage surface.

Static analysis

No suspicious patterns detected.