Back to skill

Security audit

Persona Voice

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but its transcription command can upload any readable local file path to SenseAudio, which is broader than a voice-bot skill needs.

Review this before installing in a real bot. Use it only in a constrained runtime, keep .env files protected, do not allow untrusted users or prompts to choose arbitrary --audio paths, and avoid custom Feishu/SenseAudio base URLs unless you fully trust the endpoint. Expect voice/text content and chat identifiers to leave your environment for SenseAudio and Feishu processing.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu_api.py:13
Finding

Configurable Service Endpoints Can Expose Credentials and Private Content

Content
View full analysis
None: self.base_url = get_optional('FEISHU_BASE_URL', 'https://open.feishu.cn').rstrip('/') self.app_id = get_required('FEISHU_APP_ID') self.app_secret = get_required('FEISHU_APP_SECRET') def tenant_access_token(self) -> str: resp = requests.post( f'{self.base_url}/open-apis/auth/v3/tenant_access_token/internal', headers={'Content-Type': 'application/json; charset=utf-8'}, json={'app_id': self.app_id, 'app_secret': self.app_secret}, timeout=30, ) ``` The SenseAudio clients follow the same pattern: ```python class SenseAudioASR: def __init__(self) -> None: base_url = get_optional('SENSEAUDIO_BASE_URL', 'https://api.senseaudio.cn').rstrip('/') self.api_url = f'{base_url}/v1/audio/transcriptions' self.api_key = get_required('SENSEAUDIO_API_KEY') self.model = get_optional('SENSEAUDIO_ASR_MODEL', 'sense-asr') def transcribe(self, audio_path: str | Path, language: str | None = 'zh') -> dict[str, Any]: path = Path(audio_path) with path.open('rb') as f: files = {'file': (path.name, f)} data: dict[str, Any] = {'model': self.model, 'response_format': 'json'} if language and self.model != 'sense-asr-deepthink': data['language'] = language resp = requests.post( self.api_url, headers={'Authorization': f'Bearer {self.api_key}'}, data=data, files=files, timeout=120, ...[truncated 2251 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/asr.py:18
Finding

ASR Interface Can Upload Arbitrary Process-Readable Local Files

Content
View full analysis
dict[str, Any]: path = Path(audio_path) with path.open('rb') as f: files = {'file': (path.name, f)} data: dict[str, Any] = {'model': self.model, 'response_format': 'json'} if language and self.model != 'sense-asr-deepthink': data['language'] = language resp = requests.post( self.api_url, headers={'Authorization': f'Bearer {self.api_key}'}, data=data, files=files, timeout=120, ) ``` The command-line interface accepts the path without constraints: ```python p_trans = sub.add_parser('transcribe', help='转写用户语音') p_trans.add_argument('--audio', required=True) p_trans.set_defaults(func=cmd_transcribe) ``` ### Technical Analysis The ASR implementation treats the `--audio` value as an unrestricted filesystem path. It does not verify that the resolved path: - Is located within an approved inbound-media directory. - Is a regular file rather than a symbolic link or special file. - Contains supported audio data. - Has an allowed size. - Was supplied through the expected Feishu media ingestion flow. The file is opened and transmitted in full to the configured SenseAudio endpoint. File extensions and content types are not validated. Therefore, any file readable by the Skill process can be selected for upload, even if it is not audio. The legitimate ASR feature requires access to a user-provided recording, but unrestricted access to every process-readable path exceeds the minimum filesystem scope required for that feature. ### Attack Path 1. A malicious user or ...[truncated 1016 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/main.py:27
Finding

Untrusted User Text Is Concatenated Directly into Agent Instructions

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
  • 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 (37)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 7)May include surrounding context.

python
from pathlib import Path

ROOT_DIR = Path(__file__).resolve().parent.parent
ENV_FILES = [ROOT_DIR / '.env.local', ROOT_DIR / '.env']


def load_dotenv() -> None:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 26)May include surrounding context.

python
from pathlib import Path

ROOT_DIR = Path(__file__).resolve().parent.parent
ENV_FILES = [ROOT_DIR / '.env.local', ROOT_DIR / '.env']


def load_dotenv() -> None:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 7)May include surrounding context.

python
from pathlib import Path

ROOT_DIR = Path(__file__).resolve().parent.parent
ENV_FILES = [ROOT_DIR / '.env.local', ROOT_DIR / '.env']


def load_dotenv() -> None:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill describes capabilities that imply access to environment variables, local files, shell execution, and outbound network calls, but it does not declare any explicit tool scope or permission boundaries. In an agent setting, this creates an overprivileged and opaque execution surface where the runtime may grant broader access than users or operators expect, increasing the risk of secret exposure, arbitrary command execution, and unintended data transfer.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill processes user text and audio by sending them to external services (SenseAudio for ASR/TTS and Feishu/Lark for message delivery), but the description does not clearly warn users that their content leaves the local system. This is dangerous because users may unknowingly disclose sensitive voice or text data to third parties, creating privacy, compliance, and data-governance risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The description and usage are entirely framed around Chinese-language operation and a Chinese persona-voice workflow, without offering users a language choice or documenting a justified locale restriction. This can violate language/locale policy when a skill implicitly forces a specific language or locale absent user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language persona definitions are written to produce a specific Chinese-speaking style, and the file provides no option for users to choose another language or locale. Because SQP-3 applies to all file types, this is a policy concern when a skill constrains language behavior without explicit opt-in or a documented regional justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The entire persona reference is written only in Chinese, including the title and all style instructions, with no indication that language choice is optional or that the skill is intended only for a Chinese-language context. This can constitute a language/locale policy issue because it implicitly fixes the skill experience to one language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The file title and all operational guidance are presented only in Chinese, which can constitute a language/locale policy violation when the skill documentation implicitly forces a specific language without user opt-in. There is no indication that this skill is region-specific or that alternative language documentation is available.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The method defaults the language parameter to 'zh', which imposes a specific locale unless the caller explicitly overrides it. This is a natural-language policy concern because the skill selects a language by default rather than offering a neutral default or explicit user choice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code uploads the provided audio file to an external ASR endpoint using requests.post, which creates a privacy and data-handling risk if users are not clearly informed that their voice data leaves the local/Feishu environment. In this skill context, voice messages may contain personal or sensitive content, so undisclosed transmission to a third-party transcription provider is a real security/privacy concern even if it is functionally intended.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/feishu_api.py (reported line 20)May include surrounding context.

python
self.app_secret = get_required('FEISHU_APP_SECRET')

    def tenant_access_token(self) -> str:
        resp = requests.post(
            f'{self.base_url}/open-apis/auth/v3/tenant_access_token/internal',
            headers={'Content-Type': 'application/json; charset=utf-8'},
            json={'app_id': self.app_id, 'app_secret': self.app_secret},

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code uploads audio content to Feishu without any indication here of user consent, disclosure, or minimization controls. In a chatbot or voice companion context, audio may contain sensitive personal data, so silent third-party transmission creates a real privacy and compliance risk even if it is core functionality.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from requests.post (line 27, network input) → requests.post (network output)

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

python
with path.open('rb') as f:
            files = {'file': (path.name, f, 'audio/ogg')}
            data = {'file_type': 'opus', 'file_name': path.name}
            resp = requests.post(
                f'{self.base_url}/open-apis/im/v1/files',
                headers={'Authorization': f'Bearer {token}'},
                data=data,

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/feishu_api.py (reported line 55)May include surrounding context.

python
def send_audio_message(self, chat_id: str, file_key: str) -> dict:
        token = self.tenant_access_token()
        resp = requests.post(
            f'{self.base_url}/open-apis/im/v1/messages',
            params={'receive_id_type': 'chat_id'},
            headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'},

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code sends chat message metadata/content to Feishu with no user-facing warning shown in this file. In this skill context, external delivery is expected, but lack of transparency can still expose users' communications to third-party processing without informed consent.

Content

No source excerpt is available for this finding.

Tainted flow: 'token' from requests.post (line 28, network input) → requests.post (network output)

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

python
def send_audio_message(self, chat_id: str, file_key: str) -> dict:
        token = self.tenant_access_token()
        resp = requests.post(
            f'{self.base_url}/open-apis/im/v1/messages',
            params={'receive_id_type': 'chat_id'},
            headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'},

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

python
def ensure_ffmpeg(ffmpeg_bin: str) -> None:
    try:
        proc = subprocess.run([ffmpeg_bin, '-version'], capture_output=True, text=True, check=False, timeout=10)
    except FileNotFoundError as e:
        raise RuntimeError(
            '未找到 ffmpeg。请先安装:brew install ffmpeg,或设置环境变量 FFMPEG_PATH=/opt/homebrew/bin/ffmpeg'

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

python
output = Path(output_opus)
        output.parent.mkdir(parents=True, exist_ok=True)
    cmd = [ffmpeg_bin, '-y', '-i', str(src), '-c:a', 'libopus', '-b:a', '32k', '-vbr', 'on', '-ar', '48000', str(output)]
    proc = subprocess.run(cmd, capture_output=True, text=True, check=False, timeout=120)
    if proc.returncode != 0:
        raise RuntimeError(f'音频转 OPUS 失败: {proc.stderr.strip()}')
    return output

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The send-voice command uploads generated audio and sends it to a Feishu chat via network calls, which can transmit user-provided reply content and chat metadata. In this file, there is no confirmation prompt, user-facing log message, or explanatory comment/docstring warning that the command will send data to an external service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The returned guidance string is entirely in Chinese and includes hard requirements for how replies must be written, which effectively imposes a specific language/locale behavior. There is no indication that the user can choose another language or that the locale restriction is explicitly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The transcribe method defaults the language parameter to 'zh', which imposes a specific language/locale behavior when the caller does not explicitly choose one. The policy allows language constraints only when the user is given a choice or the restriction is clearly documented and justified, neither of which is evident here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code uploads the full audio file to a third-party SenseAudio API for transcription, which can expose potentially sensitive voice content to an external service. In this skill context, users may reasonably treat voice interaction as a bot feature without realizing their recordings leave the local/bot environment, so the lack of explicit disclosure and consent increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/senseaudio_tts.py (reported line 45)May include surrounding context.

python
'sample_rate': sample_rate,
            },
        }
        resp = requests.post(
            self.api_url,
            headers={
                'Authorization': f'Bearer {self.api_key}',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The function transmits the input text and voice settings to an external HTTP endpoint, which may expose user content to a third-party service. In this file there is no confirmation prompt, logging/print statement, or explanatory comment/docstring disclosing that data leaves the local system.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.