Skip to content

🛡️ Sentinel: [MEDIUM] Fix HTML injection risk in QTextEdit - #224

Merged
dieterolson merged 2 commits into
mainfrom
sentinel/qtextedit-html-injection-10787830303746246525
Aug 11, 2026
Merged

🛡️ Sentinel: [MEDIUM] Fix HTML injection risk in QTextEdit#224
dieterolson merged 2 commits into
mainfrom
sentinel/qtextedit-html-injection-10787830303746246525

Conversation

@dieterolson

Copy link
Copy Markdown
Contributor

Severity: MEDIUM
Vulnerability: In PyQt6, QTextEdit widgets evaluate and render rich text (HTML) by default. This makes the application vulnerable to HTML injection if user input (e.g., pasted into the system prompt configuration) or programmatically appended outputs (if .append() were used) contained HTML-like content.
Impact: A user could paste malicious HTML into the configuration, or if logs/AI text generated HTML, it would render inside the desktop client leading to UI redressing or deceptive formatting.
Fix: Explicitly disabled rich text acceptance by calling .setAcceptRichText(False) on the QTextEdit instances across the application (Setup Dialog, Hub Dialog, Chat Panel, Settings Panel).
Verification: Run uv run pytest tests/unit/ to ensure no functionality is broken. Manually verify by attempting to paste HTML into the system prompt QTextEdit which will now only accept and render raw text.


PR created automatically by Jules for task 10787830303746246525 started by @dieterolson

In PyQt6 applications, `QTextEdit` widgets accept rich text (HTML) by default. If untrusted log output, generated model text, or pasted user input contains HTML tags, the widget will heuristically parse and render them. This introduces a risk of HTML injection or UI redressing, allowing attackers to maliciously format text, inject links, or break the intended display layout.

This commit explicitly sets `.setAcceptRichText(False)` on all `QTextEdit` instances (`setup_dialog.py`, `hub_dialog.py`, `chat_panel.py`, and `settings_panel.py`) to prevent HTML injection via pasted prompts or programmatic insertions if `insertPlainText()` is not strictly used.

A new entry was also added to `.jules/sentinel.md` detailing this learning.

Co-authored-by: dieterolson <198168927+dieterolson@users.noreply.github.com>
@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.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

⚠️ SPEC.md Update Required

Source files were modified in this PR but SPEC.md was not updated.

Per the Specification-Driven Development Policy:

  • Any PR that adds, removes, or changes functionality must update SPEC.md
  • Update the relevant sections (features, architecture, tests, dependencies, etc.)
  • Bump the Spec Version if making substantive changes

To resolve:

  1. Update SPEC.md to reflect your changes, OR
  2. Add the spec-exempt label if this PR genuinely doesn't affect the spec (e.g., pure refactor with no behavior change)

This check is enforced by the spec-check CI workflow.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 837fc7d10e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .jules/sentinel.md

**Vulnerability:** In PyQt6 applications, `QTextEdit` widgets accept rich text (HTML) by default. If untrusted log output, generated model text, or pasted user input contains HTML tags, the widget will render them. This introduces a risk of HTML injection or UI redressing, allowing attackers to maliciously format text, inject links, or break the intended display layout.
**Learning:** Even if `QTextEdit` is set to read-only or intended for plain text configuration (like a system prompt), it will heuristically parse pasted or programmatically inserted text as HTML unless explicitly instructed otherwise.
**Prevention:** Always apply `.setAcceptRichText(False)` to `QTextEdit` instances to enforce plain text input and display, unless rich text editing is explicitly required by the feature.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Correct the unsafe QTextEdit prevention guidance

When future code inserts untrusted output through append(), setText(), or setHtml(), setAcceptRichText(False) will not protect it because that property only restricts user-originated rich-text insertion such as paste and drag-and-drop. This new prevention rule could therefore reintroduce the exact vulnerability it claims to avoid; retain setAcceptRichText(False) for editable fields, but document insertPlainText() as required for programmatic output.

AGENTS.md reference: AGENTS.md:L25-L26

Useful? React with 👍 / 👎.

In PyQt6 applications, `QTextEdit` widgets accept rich text (HTML) by default. If untrusted log output, generated model text, or pasted user input contains HTML tags, the widget will heuristically parse and render them. This introduces a risk of HTML injection or UI redressing, allowing attackers to maliciously format text, inject links, or break the intended display layout.

This commit explicitly sets `.setAcceptRichText(False)` on all `QTextEdit` instances (`setup_dialog.py`, `hub_dialog.py`, `chat_panel.py`, and `settings_panel.py`) to prevent HTML injection via pasted prompts or programmatic insertions if `insertPlainText()` is not strictly used.

SPEC.md was also updated to reflect the new security enhancement.

Co-authored-by: dieterolson <198168927+dieterolson@users.noreply.github.com>
@dieterolson
dieterolson merged commit 49788cb into main Aug 11, 2026
6 checks passed
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