{"record":{"id":"dc095ebc6b7527b1","repo":"microsoft/autogen","slug":"video-path-must-be-a-local-file-path-not-a-url","errorCode":null,"errorMessage":"video_path must be a local file path, not a URL.","messagePattern":"video_path must be a local file path, not a URL\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py","lineNumber":28,"sourceCode":"    ChatCompletionClient,\n    UserMessage,\n)\n\n\ndef extract_audio(video_path: str, audio_output_path: str) -> str:\n    \"\"\"\n    Extracts audio from a video file and saves it as an MP3 file.\n\n    :param video_path: Path to the video file (must be a local file path, not a URL).\n    :param audio_output_path: Path to save the extracted audio file (must end with .mp3).\n    :return: Confirmation message with the path to the saved audio file.\n    \"\"\"\n    import os\n    import re\n\n    # Reject URLs to prevent SSRF via ffmpeg\n    if re.match(r\"^[a-zA-Z][a-zA-Z0-9+\\-.]*://\", video_path):\n        raise ValueError(\"video_path must be a local file path, not a URL.\")\n\n    # Enforce .mp3 extension to prevent writing arbitrary file types\n    if not audio_output_path.lower().endswith(\".mp3\"):\n        raise ValueError(\"audio_output_path must end with .mp3.\")\n\n    # Prevent path traversal — output must stay within the current working directory\n    cwd = os.path.realpath(os.getcwd())\n    output_real = os.path.realpath(audio_output_path)\n    if not output_real.startswith(cwd + os.sep) and output_real != cwd:\n        raise ValueError(\"audio_output_path must be within the current working directory.\")\n\n    (ffmpeg.input(video_path).output(audio_output_path, format=\"mp3\").run(quiet=True, overwrite_output=True))  # type: ignore\n    return f\"Audio extracted and saved to {audio_output_path}.\"\n\n\ndef transcribe_audio_with_timestamps(audio_path: str) -> str:\n    \"\"\"\n    Transcribes the audio file with timestamps using the Whisper model.","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py#L10-L46","documentation":"The extract_audio tool in autogen_ext.agents.video_surfer invokes ffmpeg on a caller-supplied video_path. As an SSRF guard it rejects any path matching a URL scheme (scheme://...) with a ValueError — video must be a local file. Only http(s), file, ftp, etc. are local to the process via ffmpeg protocol handlers, which could be abused to reach internal hosts.","triggerScenarios":"Calling extract_audio(video_path=\"https://example.com/clip.mp4\", ...) or any string with an <alpha><alnum+.->:// prefix (file://, ftp://, smb://, ...).","commonSituations":"LLM-driven VideoSurfer agents passing a scraped URL straight into the tool; user input containing a URL where a downloaded local path was expected.","solutions":["Download the video to a local file first (e.g. httpx/requests), then pass the local path to extract_audio.","Validate/sanitize model-provided arguments before tool execution so URLs never reach the tool.","In agent instructions, state that video_path must be a local file path."],"exampleFix":"# before\nextract_audio(\"https://cdn.example.com/clip.mp4\", \"/tmp/out/clip.mp3\")\n\n# after\nimport httpx\nvideo_local = \"/tmp/work/clip.mp4\"\nwith httpx.Client(follow_redirects=True) as http, open(video_local, \"wb\") as f:\n    f.write(http.get(\"https://cdn.example.com/clip.mp4\").content)\nextract_audio(video_local, \"/tmp/work/clip.mp3\")","handlingStrategy":"validation","validationCode":"import re, os\n\ndef is_local_video_path(path: str) -> bool:\n    return not re.match(r\"^[a-zA-Z][a-zA-Z0-9+\\-.]*://\", path) and os.path.exists(path)","typeGuard":"import re\n\ndef is_local_path(p: str) -> bool:\n    return isinstance(p, str) and not re.match(r\"^[a-zA-Z][a-zA-Z0-9+\\-.]*://\", p)","tryCatchPattern":null,"preventionTips":["Download remote media to a local file before calling extract_audio.","Sanitize LLM-provided tool arguments; reject scheme-prefixed paths.","Tell the model in the prompt that video_path must be local."],"tags":["video-surfer","ssrf","path-validation","ffmpeg"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}