{"record":{"id":"63dc5a3a2d444aba","repo":"microsoft/semantic-kernel","slug":"invalid-filename-would-write-outside-the-expected-63dc5a","errorCode":null,"errorMessage":"Invalid filename: would write outside the expected directory","messagePattern":"Invalid filename: would write outside the expected directory","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/samples/concepts/agents/bedrock_agent/bedrock_agent_with_code_interpreter_streaming.py","lineNumber":69,"sourceCode":"                binary_item = next((item for item in response.items if isinstance(item, BinaryContent)), None)\n        print()\n    finally:\n        # Delete the agent\n        await bedrock_agent.delete_agent()\n        await thread.delete() if thread else None\n\n    # Save the chart to a file\n    if not binary_item:\n        raise RuntimeError(\"No chart generated\")\n\n    # Securely assemble the file path and validate it's within the expected directory\n    # This is a defense-in-depth measure against directory traversal attacks\n    output_dir = Path(__file__).parent.resolve()\n    file_path = (output_dir / binary_item.metadata[\"name\"]).resolve()\n\n    # Verify the resolved path is within the expected directory\n    if not file_path.is_relative_to(output_dir):\n        raise RuntimeError(\"Invalid filename: would write outside the expected directory\")\n\n    binary_item.write_to_file(file_path)\n    print(f\"Chart saved to {file_path}\")\n\n    # Sample output (using anthropic.claude-3-haiku-20240307-v1:0):\n    # Response:\n    # Here is the bar chart for the given data:\n    # [A bar chart showing the following data:\n    # Panda   5\n    # Tiger   8\n    # Lion    3\n    # Monkey  6\n    # Dolpin  2]\n    # Chart saved to ...\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/samples/concepts/agents/bedrock_agent/bedrock_agent_with_code_interpreter_streaming.py#L51-L87","documentation":"Same path-traversal guard as error 626, in the streaming Bedrock sample. After streaming, the sample composes output_dir / binary_item.metadata['name'], resolves it, and raises RuntimeError if the resolved path is not within the script directory. It blocks writes that would escape via '..', absolute paths, or symlinked names.","triggerScenarios":"binary_item.metadata['name'] (from the streamed BinaryContent) resolves outside Path(__file__).parent - e.g. '../../x', '/abs/path', or a name with path separators that climbs out of the directory.","commonSituations":"The model/code-interpreter returns a file name containing path separators or an absolute path; a crafted/malformed metadata name; or running the sample in an environment where __file__ resolves oddly.","solutions":["Reduce the name to its basename with os.path.basename before joining.","Regenerate the chart asking the model for a simple filename if it returned a path-like name.","Write to a dedicated safe output subdir using a generated name.","Keep the is_relative_to check as a secondary guard."],"exampleFix":"# before\noutput_dir = Path(__file__).parent.resolve()\nfile_path = (output_dir / binary_item.metadata[\"name\"]).resolve()\nif not file_path.is_relative_to(output_dir):\n    raise RuntimeError(\"Invalid filename: would write outside the expected directory\")\n# after\nimport os\nfile_path = (output_dir / os.path.basename(binary_item.metadata[\"name\"])).resolve()\nif not file_path.is_relative_to(output_dir):\n    raise RuntimeError(\"Invalid filename: would write outside the expected directory\")","handlingStrategy":"validation","validationCode":"import os\nfrom pathlib import Path\n\ndef safe_join(output_dir: Path, name: str) -> Path:\n    safe = os.path.basename(str(name))\n    target = (output_dir / safe).resolve()\n    if not target.is_relative_to(output_dir.resolve()):\n        raise RuntimeError(f\"Refusing to write outside {output_dir}: {name!r}\")\n    return target","typeGuard":"def is_safe_filename(name: object) -> bool:\n    s = str(name or \"\")\n    return bool(s) and os.path.basename(s) == s and \"/\" not in s and \"\\\\\" not in s and \"..\" not in s","tryCatchPattern":"try:\n    file_path = safe_join(output_dir, binary_item.metadata[\"name\"])\n    binary_item.write_to_file(file_path)\nexcept RuntimeError as e:\n    logger.error(\"Refused unsafe write: %s\", e)","preventionTips":["Reduce streamed filenames to basename before composing paths.","Keep the is_relative_to guard after resolve().","Write to a dedicated safe output directory using a generated name."],"tags":["python","sample","path-traversal","security","bedrock","streaming"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}