OpenBMB / OpenBMB/PilotDeck

Cover HTML renderer inserts raw document metadata as markup

Open
#416 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
4k
Forks
453
Avg merge
12h 30m
Merged PRs (30d)
46

Description

Summary

skills/minimax-pdf/scripts/cover.py interpolates user-controlled document tokens directly into generated cover HTML. Values such as title, subtitle, and similar metadata are inserted without HTML escaping, so plain text containing markup is rendered as real HTML instead of text. This can break generated covers and can execute active markup if the HTML is opened in a browser or converted by an HTML renderer that honors scripts/events.

Code path

  • skills/minimax-pdf/scripts/cover.py:83-89 builds the optional subtitle block with raw t['subtitle'].
  • skills/minimax-pdf/scripts/cover.py:142, 219, 353, 459, 567, 669, 822, 961, 1063, 1165, 1332, and 1494 insert raw t['title'] across cover patterns.
  • skills/minimax-pdf/scripts/cover.py:1532-1536 dispatches the selected pattern from render(tokens).
  • skills/minimax-pdf/scripts/cover.py:1548-1562 reads tokens.json and optional --subtitle before rendering the HTML file.

Steps to reproduce

Validation level: dynamic reproduction plus source-control-flow inspection.

import importlib.util
from pathlib import Path

def load_module(rel_path):
    path = Path(rel_path)
    spec = importlib.util.spec_from_file_location(path.stem, path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

palette = load_module("skills/minimax-pdf/scripts/palette.py")
cover = load_module("skills/minimax-pdf/scripts/cover.py")

payload = "<script>alert(1)</script>"
tokens = palette.build_tokens(title=payload, doc_type="academic", author=payload)
tokens["subtitle"] = payload
html = cover.render(tokens)

print(payload in html)
print(html[html.find(payload) - 60 : html.find(payload) + len(payload) + 60])

Observed output:

True
<div class="first-word"><script>alert(1)</script></div>

Expected behavior

Document metadata should be treated as text by default. If a title, subtitle, or author contains characters such as <, >, or &, the generated cover should contain escaped text such as &lt;script&gt;...&lt;/script&gt;, not executable HTML.

Actual behavior

The generated cover HTML contains the raw payload. This turns text metadata into markup and may execute active content when the cover HTML is viewed or processed by an HTML renderer.

Existing coverage

I searched current issues and PRs for cover.py, cover.render, _pattern_*, title, subtitle, script, html escape, XSS, and minimax-pdf. I did not find an existing issue or PR that covers this root cause.

Suggested fix

Escape text-valued tokens before interpolation into HTML, for example with html.escape(..., quote=True). Keep CSS/color/font tokens validated separately instead of blindly escaping every token, because those values are used inside CSS declarations.

A small helper such as text_token(t, key) could make the pattern templates consistent and avoid missing one cover pattern.

Suggested tests

  • Add a regression test that renders every cover pattern with a title like <script>alert(1)</script> and asserts the raw payload is absent while the escaped text is present.
  • Add a subtitle-specific test, because --subtitle can override the token value at the CLI layer.
  • Add a test for ordinary text containing & and <2026> to ensure non-malicious markup-like titles are displayed literally.

Submitted with Codex.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in skills/minimax-pdf/scripts/cover.py, especially the subtitle block at lines 83-89, the listed title interpolations, and render(tokens). Reproduce the issue with the provided script, then inspect every cover pattern for text-valued metadata. Done means title and subtitle markup-like text is escaped in all patterns, CSS-related tokens remain separately validated, and regression tests cover titles, subtitles, ampersands, and every pattern.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.