From 3cd51be165ade65dd8c28ec52a87d94408b20dcc Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 00:21:20 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20command=20injection=20in=20PDF=20compilation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: anchapin <6326294+anchapin@users.noreply.github.com> --- cli/generators/cover_letter_generator.py | 27 ++++++++++++++++++++---- cli/pdf/converter.py | 25 ++++++++++++++++++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/cli/generators/cover_letter_generator.py b/cli/generators/cover_letter_generator.py index aaf0b61..6b93e9e 100644 --- a/cli/generators/cover_letter_generator.py +++ b/cli/generators/cover_letter_generator.py @@ -771,12 +771,18 @@ def _compile_pdf(self, output_path: Path, tex_content: str) -> bool: try: # Use Popen with explicit cleanup to avoid double-free issues process = subprocess.Popen( - ["pdflatex", "-interaction=nonstopmode", tex_path.name], + ["pdflatex", "-interaction=nonstopmode", "-no-shell-escape", tex_path.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=tex_path.parent, ) - stdout, stderr = process.communicate() + try: + stdout, stderr = process.communicate(timeout=30) + except subprocess.TimeoutExpired: + process.kill() + stdout, stderr = process.communicate() + raise RuntimeError("PDF compilation timed out") + if process.returncode == 0 or output_path.exists(): pdf_created = True except (subprocess.CalledProcessError, FileNotFoundError): @@ -787,11 +793,24 @@ def _compile_pdf(self, output_path: Path, tex_content: str) -> bool: # Fallback to pandoc try: process = subprocess.Popen( - ["pandoc", str(tex_path), "-o", str(output_path), "--pdf-engine=xelatex"], + [ + "pandoc", + str(tex_path), + "-o", + str(output_path), + "--pdf-engine=xelatex", + "--pdf-engine-opt=-no-shell-escape", + ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) - stdout, stderr = process.communicate() + try: + stdout, stderr = process.communicate(timeout=30) + except subprocess.TimeoutExpired: + process.kill() + stdout, stderr = process.communicate() + raise RuntimeError("PDF compilation timed out") + if process.returncode == 0 or output_path.exists(): pdf_created = True except (subprocess.CalledProcessError, FileNotFoundError): diff --git a/cli/pdf/converter.py b/cli/pdf/converter.py index 0b0a200..d78222e 100644 --- a/cli/pdf/converter.py +++ b/cli/pdf/converter.py @@ -86,12 +86,17 @@ def _compile_pdflatex( """ try: process = subprocess.Popen( - ["pdflatex", "-interaction=nonstopmode", tex_path.name], + ["pdflatex", "-interaction=nonstopmode", "-no-shell-escape", tex_path.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=working_dir, ) - stdout, stderr = process.communicate() + try: + stdout, stderr = process.communicate(timeout=30) + except subprocess.TimeoutExpired: + process.kill() + stdout, stderr = process.communicate() + raise RuntimeError("PDF compilation timed out") if process.returncode == 0 or output_path.exists(): return True @@ -121,12 +126,24 @@ def _compile_pandoc( """ try: process = subprocess.Popen( - ["pandoc", str(tex_path), "-o", str(output_path), "--pdf-engine=xelatex"], + [ + "pandoc", + str(tex_path), + "-o", + str(output_path), + "--pdf-engine=xelatex", + "--pdf-engine-opt=-no-shell-escape", + ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=working_dir, ) - stdout, stderr = process.communicate() + try: + stdout, stderr = process.communicate(timeout=30) + except subprocess.TimeoutExpired: + process.kill() + stdout, stderr = process.communicate() + raise RuntimeError("PDF compilation timed out") if process.returncode == 0 or output_path.exists(): return True