Back to skill

Security audit

Ali Feishu Sender

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it can send media externally to Feishu immediately and can overwrite local converted media files without safeguards.

Review this before installing if you will use it with private media or workplace chats. Configure credentials and recipients deliberately, confirm what will be sent before invoking it, and avoid running audio/video conversion in shared or untrusted directories until the overwrite and cleanup behavior is fixed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu_media.py:89
Finding

Predictable Media Conversion Paths Allow Local File Clobbering

Content
View full analysis
0 ``` ```python def send_audio(filepath, open_id=None, token=None, **kwargs): """Send audio as native voice bubble. Auto-converts to opus, always includes duration.""" token = token or get_token(kwargs.get('app_id'), kwargs.get('app_secret')) ffmpeg = kwargs.get('ffmpeg') ffprobe = kwargs.get('ffprobe') # Convert to opus if needed if not filepath.lower().endswith('.opus'): opus_path = os.path.splitext(filepath)[0] + '.opus' if not _to_opus(filepath, opus_path, ffmpeg): return {'code': -1, 'msg': 'Failed to convert to opus'} filepath = opus_path duration = _get_duration_ms(filepath, ffprobe) or 0 r = _multipart_upload(UPLOAD_API, {'file_type': 'opus', 'file_name': os.path.basename(filepath), 'duration': str(duration)}, ('file', filepath), token) if r['code'] != 0: return r return _send_msg(token, open_id or DEFAULT_OPEN_ID, 'audio', {'file_key': r['data']['file_key']}) def send_video(filepath, cover_image=None, open_id=None, token=None, **kwargs): """Send video as inline player. Auto-applies faststart, always includes duration.""" token = token or get_token(kwargs.get('app_id'), kwargs.get('app_ ...[truncated 3211 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (16)

Tainted flow: 'req' from os.environ.get (line 21, credential/environment) → urllib.request.urlopen (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 · scripts/feishu_media.py (reported line 22)May include surrounding context.

python
def get_token(app_id=None, app_secret=None):
    data = json.dumps({'app_id': app_id or DEFAULT_APP_ID, 'app_secret': app_secret or DEFAULT_APP_SECRET}).encode()
    req = urllib.request.Request(TOKEN_API, data=data, headers={'Content-Type': 'application/json'})
    return json.loads(urllib.request.urlopen(req).read())['tenant_access_token']


def _safe_response(resp_or_error):

Tainted flow: 'req' from os.environ.get (line 21, credential/environment) → urllib.request.urlopen (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 · scripts/feishu_media.py (reported line 54)May include surrounding context.

python
'Content-Type': 'multipart/form-data; boundary=' + boundary
    })
    try:
        return json.loads(urllib.request.urlopen(req).read())
    except urllib.error.HTTPError as e:
        raw = e.read()
        try:

Tainted flow: 'req' from os.environ.get (line 21, credential/environment) → urllib.request.urlopen (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 · scripts/feishu_media.py (reported line 68)May include surrounding context.

python
'Content-Type': 'multipart/form-data; boundary=' + boundary
    })
    try:
        return json.loads(urllib.request.urlopen(req).read())
    except urllib.error.HTTPError as e:
        raw = e.read()
        try:

Tainted flow: 'req' from os.environ.get (line 21, credential/environment) → urllib.request.urlopen (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 · scripts/feishu_media.py (reported line 113)May include surrounding context.

python
'Authorization': 'Bearer ' + token,
        'Content-Type': 'multipart/form-data; boundary=' + boundary
    })
    return json.loads(urllib.request.urlopen(req).read())['data']['image_key']


# ============ PUBLIC API ============

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill exposes capabilities that imply environment access, network communication, and shell execution, but it does not declare any tool scope or permission boundaries. That makes the skill harder to review safely and increases the chance of unintended command execution, credential access, or outbound data transmission during normal use.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger conditions include broad phrases like sending to Feishu/Lark, which can match common user wording and cause the skill to activate when the user did not intend external transmission. In a skill that performs networked delivery of user-generated media, accidental activation can lead to unintended sharing of sensitive content with third-party recipients.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation describes sending content to Feishu and using credentials, but it does not warn users that data and authentication material may be transmitted to an external API. That omission weakens informed consent and can cause users to expose private files, media, or organizational data without understanding the external boundary.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Stating that Feishu app credentials are pre-configured in script defaults strongly suggests embedded or default secrets may exist in the skill implementation. Embedded credentials are dangerous because they can be exposed, reused without user awareness, and enable unauthorized use of the Feishu tenant or API outside the intended workflow.

Content

No source excerpt is available for this finding.

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_media.py (reported line 79)May include surrounding context.

python
def _get_duration_ms(filepath, ffprobe=None):
    ffprobe = ffprobe or DEFAULT_FFPROBE
    r = subprocess.run([ffprobe, '-v', 'quiet', '-print_format', 'json', '-show_format', filepath],
                       capture_output=True, text=True)
    if r.returncode != 0:
        return None

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_media.py (reported line 88)May include surrounding context.

python
def _to_opus(src, dst, ffmpeg=None):
    ffmpeg = ffmpeg or DEFAULT_FFMPEG
    r = subprocess.run([ffmpeg, '-y', '-i', src, '-c:a', 'libopus', '-b:a', '32k', dst], capture_output=True)
    return r.returncode == 0 and os.path.exists(dst)

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_media.py (reported line 94)May include surrounding context.

python
def _faststart_mp4(src, dst, ffmpeg=None):
    ffmpeg = ffmpeg or DEFAULT_FFMPEG
    r = subprocess.run([ffmpeg, '-y', '-i', src, '-c', 'copy', '-movflags', '+faststart', dst], capture_output=True)
    return r.returncode == 0 and os.path.exists(dst) and os.path.getsize(dst) > 0

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill transmits text, images, audio, video, and rich content to Feishu without any built-in consent, warning, or confirmation mechanism. In an agent setting, this can cause inadvertent disclosure of sensitive user content or generated media to external recipients, especially because the tool is expressly designed for outbound sharing.

Content

No source excerpt is available for this finding.

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_media.py (reported line 160)May include surrounding context.

python
# Ensure mp4 + faststart
    if not filepath.lower().endswith('.mp4'):
        mp4_path = os.path.splitext(filepath)[0] + '.mp4'
        subprocess.run([ffmpeg or DEFAULT_FFMPEG, '-y', '-i', filepath, '-c', 'copy', '-movflags', '+faststart', mp4_path], capture_output=True)
        if os.path.exists(mp4_path):
            filepath = mp4_path
    else:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The rich text payload is built only under the zh_cn key, which forces a specific language/locale in the message structure. The file does not offer an option to select another locale or explain why Chinese locale is required, which matches the policy concern about locale being imposed without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The example rich-text message uses Chinese title and body text, which may imply a fixed language default in user-facing output without stating that language is configurable. The file does not explicitly offer a language or locale choice for generated message content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The file automatically accesses FEISHU_APP_ID, FEISHU_APP_SECRET, and FEISHU_OPEN_ID from the environment, which are sensitive values, but there is no warning in the CLI description or output that these credentials and identifiers are being used. For a user invoking the script, this credential dependency is implicit rather than clearly disclosed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.