Skip to content

πŸ›‘οΈ Sentinel: [CRITICAL] Fix command injection and timeout in PDF generation - #368

Open
anchapin wants to merge 2 commits into
mainfrom
sentinel-pdf-security-fixes-3257995907454688652
Open

πŸ›‘οΈ Sentinel: [CRITICAL] Fix command injection and timeout in PDF generation#368
anchapin wants to merge 2 commits into
mainfrom
sentinel-pdf-security-fixes-3257995907454688652

Conversation

@anchapin

@anchapin anchapin commented Jun 19, 2026

Copy link
Copy Markdown
Owner

🚨 Severity: CRITICAL
πŸ’‘ Vulnerability: The pdflatex and pandoc commands were missing the -no-shell-escape flag, allowing potential Remote Code Execution (RCE) if malicious LaTeX was compiled. Furthermore, the subprocess calls lacked a timeout, making the application vulnerable to Denial of Service (DoS) attacks via infinite compilation loops.
🎯 Impact: A malicious user could execute arbitrary shell commands on the host server by injecting \write18 or \input{|...} into the LaTeX template inputs. Additionally, malformed LaTeX could cause the process to hang indefinitely, starving the server of resources.
πŸ”§ Fix: Enforced -no-shell-escape for pdflatex and --pdf-engine-opt=-no-shell-escape for pandoc. Added a 30-second timeout to all subprocess.communicate() calls, catching TimeoutExpired, explicitly killing the process, and returning False gracefully. Added test cases to tests/test_pdf_security.py to ensure these arguments and timeouts are enforced.
βœ… Verification: Ran the full test suite (python -m pytest), achieving 100% pass rate. Verified new security tests validate the correct flags and timeout handling. Code was formatted with black.


PR created automatically by Jules for task 3257995907454688652 started by @anchapin

Summary by Sourcery

Harden PDF generation against command injection and hangs by tightening LaTeX/pandoc invocation and adding timeouts.

Bug Fixes:

  • Prevent potential command injection in pdflatex and pandoc calls by enforcing no-shell-escape options in PDF generation paths.
  • Avoid indefinite hangs during PDF compilation by adding timeouts, killing stuck subprocesses, and failing gracefully on timeout.

Documentation:

  • Extend the Sentinel security log with an entry describing the LaTeX command injection and timeout vulnerabilities, learnings, and preventive measures.

Tests:

  • Add unit tests for PDFConverter and CoverLetterGenerator to verify pdflatex is invoked with no-shell-escape and that timeouts result in process termination and a false return value.

Added `-no-shell-escape` flag and 30-second timeouts to `pdflatex` and
`pandoc` compilation commands in `cli/pdf/converter.py` and
`cli/generators/cover_letter_generator.py` to prevent Remote Code
Execution (RCE) and Denial of Service (DoS) attacks. Added tests to
verify the fixes.

Co-authored-by: anchapin <[email protected]>
@google-labs-jules

Copy link
Copy Markdown
Contributor

πŸ‘‹ Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a πŸ‘€ emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@sourcery-ai

sourcery-ai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Reviewer's Guide

Enforces secure and resilient PDF generation by adding no-shell-escape flags and timeouts around LaTeX/Pandoc subprocesses, plus regression tests and sentinel documentation for the security fixes.

Sequence diagram for secure PDF generation with no-shell-escape and timeout

sequenceDiagram
    actor User
    participant CoverLetterGenerator
    participant PdfConverter as PdfConverter
    participant Pdflatex as subprocess_Pdflatex
    participant Pandoc as subprocess_Pandoc

    User->>CoverLetterGenerator: generate_cover_letter_pdf
    CoverLetterGenerator->>PdfConverter: _compile_pdflatex(tex_path, output_path, working_dir)
    PdfConverter->>Pdflatex: subprocess.Popen(["pdflatex", "-interaction=nonstopmode", "-no-shell-escape", tex_path.name])
    Pdflatex-->>PdfConverter: process
    PdfConverter->>Pdflatex: process.communicate(timeout=30)

    alt pdflatex_timeout
        Pdflatex-->>PdfConverter: subprocess.TimeoutExpired
        PdfConverter->>Pdflatex: process.kill()
        PdfConverter->>Pdflatex: process.communicate()
        PdfConverter-->>CoverLetterGenerator: False
    else pdflatex_success
        Pdflatex-->>PdfConverter: stdout, stderr
        PdfConverter-->>CoverLetterGenerator: True
    else pdflatex_failure
        PdfConverter->>PdfConverter: _compile_pandoc(tex_path, output_path, working_dir)
        PdfConverter->>Pandoc: subprocess.Popen(["pandoc", tex_path, "-o", output_path, "--pdf-engine=xelatex", "--pdf-engine-opt=-no-shell-escape"]) 
        Pandoc-->>PdfConverter: process
        PdfConverter->>Pandoc: process.communicate(timeout=30)
        alt pandoc_timeout
            Pandoc-->>PdfConverter: subprocess.TimeoutExpired
            PdfConverter->>Pandoc: process.kill()
            PdfConverter->>Pandoc: process.communicate()
            PdfConverter-->>CoverLetterGenerator: False
        else pandoc_complete
            Pandoc-->>PdfConverter: stdout, stderr
            PdfConverter-->>CoverLetterGenerator: True/False
        end
    end
Loading

File-Level Changes

Change Details Files
Harden pdflatex and pandoc invocation in the generic PDF converter against command injection and hangs.
  • Add -no-shell-escape to the pdflatex command used for LaTeX compilation.
  • Extend pandoc invocation to pass --pdf-engine-opt=-no-shell-escape alongside the xelatex engine.
  • Wrap subprocess.communicate() calls with a 30-second timeout and handle TimeoutExpired by killing the process, draining output, and returning False on failure.
cli/pdf/converter.py
Secure the CoverLetterGenerator PDF compilation path with no-shell-escape and subprocess timeouts.
  • Ensure pdflatex is invoked with -no-shell-escape in addition to -interaction=nonstopmode when compiling cover letter PDFs.
  • Add a 30-second timeout to both pdflatex and pandoc subprocess.communicate() calls, killing the process and returning False on timeout.
  • Refactor imports slightly so subprocess is available where timeout handling is added.
cli/generators/cover_letter_generator.py
Introduce regression tests to validate PDF security flags and timeout behavior for the converter and cover letter generator.
  • Mock subprocess.Popen to simulate TimeoutExpired and successful runs, asserting process.kill() is called and timeouts are passed to communicate().
  • Verify that pdflatex invocations include -no-shell-escape, -interaction=nonstopmode, and the pdflatex binary for both the converter and cover letter generator.
  • Set up minimal Config and ResumeYAML mocks to construct a CoverLetterGenerator instance for testing its private compilation method.
tests/test_pdf_security.py
Document the new critical PDF generation hardening in the Sentinel security log.
  • Add an entry describing the missing no-shell-escape flags and subprocess timeouts as a critical vulnerability.
  • Capture the key learning about LaTeX/Pandoc shell execution and the need for timeouts in automated workflows.
  • Record concrete prevention guidance mandating no-shell-escape flags and timeout + kill handling for subprocess calls.
.jules/sentinel.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The timeout/kill/communicate pattern for pdflatex and pandoc is duplicated in multiple places; consider extracting a small helper (e.g., run_with_timeout(cmd, cwd=None, timeout=30)) to centralize this behavior and reduce the risk of inconsistent future changes.
  • In _compile_pdf you now import subprocess inside the method while cli/pdf/converter.py uses a module-level import; aligning these to a single import style (preferably at the top of the file) will keep the codebase more consistent and avoid subtle mocking differences in tests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The timeout/kill/communicate pattern for `pdflatex` and `pandoc` is duplicated in multiple places; consider extracting a small helper (e.g., `run_with_timeout(cmd, cwd=None, timeout=30)`) to centralize this behavior and reduce the risk of inconsistent future changes.
- In `_compile_pdf` you now import `subprocess` inside the method while `cli/pdf/converter.py` uses a module-level import; aligning these to a single import style (preferably at the top of the file) will keep the codebase more consistent and avoid subtle mocking differences in tests.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.

Added `-no-shell-escape` flag and 30-second timeouts to `pdflatex` and
`pandoc` compilation commands in `cli/pdf/converter.py` and
`cli/generators/cover_letter_generator.py` to prevent Remote Code
Execution (RCE) and Denial of Service (DoS) attacks. Added tests to
verify the fixes.

Co-authored-by: anchapin <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant