Back to skill

Security audit

Voice Note Transcriber

Security checks for vulnerabilities and agentic risk

Overview

The skill largely does what it claims, but it handles email credentials and voice recordings while using unsafe file-write and API-key handling patterns that deserve manual review before installation.

Install only if you are comfortable giving the skill mailbox credentials, uploading matching audio attachments to OpenAI, and allowing it to write Markdown notes and mark emails as read. Use an app-specific email password, a limited OpenAI key if available, set MARK_EMAIL_READ=false unless wanted, and keep FLEETING_FOLDER to a simple relative folder under the vault.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/transcribe_voice_notes.py:77
Finding

OpenAI API Key Exposed Through Process Arguments

Content
View full analysis
str: """Transcribe audio via OpenAI Whisper API (curl).""" cmd = [ "curl", "-sS", "https://api.openai.com/v1/audio/transcriptions", "-H", f"Authorization: Bearer {OPENAI_API_KEY}", "-F", f"file=@{audio_path}", "-F", "model=whisper-1", "-F", "response_format=json", ] result = subprocess.run(cmd, capture_output=True, text=True) ``` ### Technical Analysis The OpenAI API key is placed directly in the argument vector of a spawned `curl` process. Although the authorization header is transmitted over HTTPS, putting the credential in the command-line arguments can expose it locally through process inspection facilities, monitoring agents, diagnostic tools, audit logs, or process telemetry. On systems where process arguments are visible to other users or services, the bearer token may be recovered while the `curl` process is running. The use of an argument array prevents shell injection, but it does not protect the confidentiality of arguments. Uploading selected audio to OpenAI is necessary for the declared cloud-transcription functionality and is disclosed in `SKILL.md`. The vulnerability is therefore not the network transmission itself, but the insecure local handling of the API credential. ### Attack Path 1. A user starts the voice-note transcription Skill. 2. The Skill spawns `curl` with the OpenAI bearer token embedded in its argument vector. 3. A local user, monitoring agent, or compromised process inspects process command lines while the request is active. 4. The observer extracts the API key from the `Authorization: Bearer ...` argument. 5. The stolen key is reused from another system to make requests under the victim's OpenAI ac ...[truncated 472 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/transcribe_voice_notes.py:69
Finding

Obsidian Vault Write Boundary Can Be Bypassed

Content
View full analysis
str: """Return the absolute path to the fleeting notes folder inside the vault.""" path = os.path.join(OBSIDIAN_VAULT_PATH, FLEETING_FOLDER) os.makedirs(path, exist_ok=True) return path ``` ```python def save_note(transcript: str, subject: str, sender: str, date_str: str) -> str: """Write a fleeting note to the Obsidian vault and return its path.""" today = datetime.now(timezone.utc).strftime("%Y-%m-%d") timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d_%H%M%S") filename = f"{timestamp} Voice Note.md" filepath = os.path.join(fleeting_path(), filename) content = f"""--- tags: - type/transcript - source/voice-note date: {today} email_subject: "{subject}" email_from: "{sender}" --- # Voice Note Transcript — {today} ## Transcript {transcript} ## Source - **Subject:** {subject} - **From:** {sender} - **Date:** {date_str} """ with open(filepath, "w", encoding="utf-8") as f: f.write(content) return filepath ``` ### Technical Analysis `FLEETING_FOLDER` is documented as a path relative to the configured Obsidian vault, but the implementation does not enforce that restriction. If `FLEETING_FOLDER` is absolute, `os.path.join(OBSIDIAN_VAULT_PATH, FLEETING_FOLDER)` discards the vault prefix. If it contains parent traversal components such as `../`, the normalized destination can escape the vault. The code then creates the resulting directory with `os.makedirs()` and writes a Markdown file there. Consequently, the filesystem access granted to this Skill exceeds the least privilege declared by its functionality. It can write outside the Obsidian vault anywhere the operating-system account has permission. The generated f ...[truncated 1436 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/transcribe_voice_notes.py:107
Finding

Untrusted Email Headers Can Inject Obsidian YAML Frontmatter

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares powerful behavior—reading environment secrets, executing a Python script, and writing files into an Obsidian vault—but does not declare an explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and makes it harder for a user or platform to understand and constrain what the skill can access before execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill sends audio email attachments to the OpenAI Whisper API for transcription, but the description does not clearly warn users that third-party processing occurs and that related content or metadata may leave the local environment. This can lead to unintended disclosure of sensitive voice content and associated email context, especially because emails often contain personal or business information.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script claims to save notes inside the Obsidian vault, but FLEETING_FOLDER is joined directly with the vault path without validation. If this value is absolute or contains path traversal such as '../', transcripts can be written outside the intended vault boundary, causing unauthorized file writes and possible data overwrite in other locations accessible to the process.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The script sends email attachment contents to an external OpenAI transcription endpoint. Because attachments may contain sensitive voice data and associated metadata, this creates a confidentiality and compliance risk if users do not clearly understand that data leaves the local environment.

Content

Scanner excerpt · scripts/transcribe_voice_notes.py (reported line 70)May include surrounding context.

python
def transcribe(audio_path: str) -> str:
    """Transcribe audio via OpenAI Whisper API (curl)."""
    cmd = [
        "curl", "-sS", "https://api.openai.com/v1/audio/transcriptions",
        "-H", f"Authorization: Bearer {OPENAI_API_KEY}",
        "-F", f"file=@{audio_path}",
        "-F", "model=whisper-1",

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/transcribe_voice_notes.py (reported line 76)May include surrounding context.

python
"-F", "model=whisper-1",
        "-F", "response_format=json",
    ]
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"  Whisper API error: {result.stderr.strip()}")
        return ""

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

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/transcribe_voice_notes.py (reported line 76)May include surrounding context.

python
"-F", "model=whisper-1",
        "-F", "response_format=json",
    ]
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"  Whisper API error: {result.stderr.strip()}")
        return ""

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill can mark processed emails as read, which changes mailbox state, but this side effect is not prominently disclosed as a warning. Users may unintentionally lose their unread triage state or interfere with other workflows that depend on unread messages as signals.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill alters mailbox state by marking processed emails as read, which is a side effect beyond simple fetching and transcription. In automation contexts, this can hide unread messages from users or downstream workflows and may cause missed review of important emails.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.