T09 · Insecure Skill Coding Practices
- Location
scripts/send_ab_variants_to_feishu.py:134- Finding
Arbitrary Local Audio File Disclosure Through Feishu Delivery
- Content
View full analysis
Vulnerability Details
File Location:
scripts/send_ab_variants_to_feishu.py, lines 134-183
Vulnerability Type: Unvalidated local file reference leading to data disclosure
Risk Level: HighVulnerable Code
python tts_results_path = Path(args.tts_results).expanduser().resolve() summary = load_json(tts_results_path) selected_results = filter_results(summary.get("results") or [], args.variant_ids, args.limit) if not selected_results: raise SystemExit("no variants selected for Feishu sending") workspace_root = Path(args.workspace_root).expanduser().resolve() config = feishu_sender.load_feishu_config(Path(args.config_path).expanduser()) chat_id, session_path = feishu_sender.infer_chat_id( workspace_root, args.chat_id.strip(), args.session_file.strip(), ) tenant_token = feishu_sender.fetch_tenant_token( config["app_id"], config["app_secret"], ) deliveries = [] for index, item in enumerate(selected_results, start=1): source_path = Path(str(item.get("out_path") or "")).expanduser().resolve() if not source_path.exists(): raise SystemExit(f"missing synthesized audio file: {source_path}") target_name = ( f"{item.get('variant_id', f'V{index:02d}')}_" f"{slugify(str(item.get('tone') or 'tone'))}_" f"{slugify(str(item.get('regional_style') or 'style'))}.ogg" ) target_path = prepared_dir / target_name transcode_to_ogg(source_path, target_path, ffmpeg_exe=ffmpeg_exe) duration_ms = (((item.get("extra_info") or {}).get("audio_length")) or None) upload = feishu_sender.upload_audio(target_path, tenant_token, duration_ms) file_key = (((upload.get("data") or {}).get("file_key")) or "").strip() if not file_key: raise SystemExit( f"upload response missing file_key: {json.dumps(upload, ensure_ascii=False)}" ) send = feishu_sender.send_audio_message(chat_ ...[truncated 2195 chars]- Remediation
View remediation
Remediation Suggestions
- Derive the permitted source directory from a trusted pipeline output rather than from caller-controlled JSON.
- Resolve both the trusted root and candidate path, then require the candidate to remain inside that root:
python trusted_root = tts_results_path.parent.resolve() source_path = Path(str(item.get("out_path") or "")).expanduser().resolve(strict=True) if not source_path.is_relative_to(trusted_root): raise SystemExit("audio source is outside the trusted TTS output directory") - Require
source_path.is_file()and reject symbolic links before reading or transcoding. - Build the allowed file list from a trusted manifest generated during the same pipeline invocation.
- Require explicit recipient confirmation before sending to an inferred chat, especially when no
--chat-idwas supplied. - Use narrowly scoped Feishu application permissions limited to uploading media and sending messages only where necessary.
- Record a non-sensitive audit event containing the validated source identifier and destination chat without logging credentials or tenant tokens.
