High severity8.6NVD Advisory· Published May 4, 2026· Updated May 5, 2026
CVE-2026-42079
CVE-2026-42079
Description
PPTAgent is an agentic framework for reflective PowerPoint generation. Prior to commit 418491a, PPTAgent is vulnerable to arbitrary code execution via Python eval() of LLM-generated code with builtins in scope. This issue has been patched via commit 418491a.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pptagentPyPI | < 1.1.36 | 1.1.36 |
Affected products
1Patches
13 files changed · +30 −5
pptagent/apis.py+2 −1 modified@@ -23,6 +23,7 @@ logger = get_logger(__name__) TABLE_REGEX = re.compile(r".*table_[0-9a-fA-F]{4}\.png$") +SAFE_EVAL_GLOBALS = {"__builtins__": {}} class SlideRenderer(HTMLRenderer): @@ -182,7 +183,7 @@ def execute_actions( partial_func = partial(self.registered_functions[func], edit_slide) if func == "replace_image": partial_func = partial(partial_func, doc) - eval(line, {}, {func: partial_func}) + eval(line, SAFE_EVAL_GLOBALS, {func: partial_func}) self.code_history[-1][0] = HistoryMark.CODE_RUN_CORRECT except Exception as e: if not isinstance(e, SlideEditError):
pptagent/mcp_server.py+3 −2 modified@@ -23,6 +23,7 @@ get_html_table_image, get_logger, package_join, + resolve_path_in_workspace, ) logger = get_logger(__name__) @@ -291,13 +292,13 @@ async def save_generated_slides(pptx_path: str): Args: pptx_path: The path to save the PowerPoint file """ - pptx = Path(pptx_path) + pptx = resolve_path_in_workspace(pptx_path) assert len(self.slides), ( "No slides generated, please call `generate_slide` first" ) pptx.parent.mkdir(parents=True, exist_ok=True) self.empty_prs.slides = self.slides - self.empty_prs.save(pptx_path) + self.empty_prs.save(str(pptx)) self.slides = [] self._initialized = False return f"total {len(self.empty_prs.slides)} slides saved to {pptx}"
pptagent/utils.py+25 −2 modified@@ -98,6 +98,28 @@ def get_logger(name="pptagent", level=None): "unoconvert/soffice is not installed, pptx to images conversion will not work" ) + +def resolve_path_in_workspace(path_str: str, workspace: Path | None = None) -> Path: + """ + Resolve a path and ensure it stays inside the active workspace. + + Args: + path_str (str): User-provided file path. + workspace (Path | None): Allowed workspace root. Defaults to current working + directory. + + Returns: + Path: Resolved path within the workspace. + """ + workspace_root = (workspace or Path.cwd()).resolve() + target = Path(path_str).resolve() + if not target.is_relative_to(workspace_root): + raise ValueError( + f"Access denied: path outside allowed workspace: {workspace_root}" + ) + return target + + # Set of supported image extensions IMAGE_EXTENSIONS: set[str] = { "bmp", @@ -347,7 +369,8 @@ def get_html_table_image(html: str, output_path: str, css: str = None): """ if css is None: css = TABLE_CSS - parent_dir, base_name = os.path.split(output_path) + output_file = resolve_path_in_workspace(output_path) + parent_dir, base_name = os.path.split(output_file) if parent_dir and not os.path.exists(parent_dir): os.makedirs(parent_dir) @@ -364,7 +387,7 @@ def get_html_table_image(html: str, output_path: str, css: str = None): save_as=base_name, size=(1000, 600), ) - manual_scan_crop(output_path) + manual_scan_crop(str(output_file)) async def _is_unoserver_running(host: str, port: int) -> bool:
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.