PaddleOCR table blocks are stored as raw HTML in table_content / Document.text and metadata["table_origin"]. That HTML is later shown in the UI without sanitization (Markdown passthrough + gr.HTML), and embedded in reasoning evidence as raw HTML. Because OCR output can contain arbitrary strings (including HTML/script), this is a potential stored XSS when viewing chunks or evidence
Affected code
| Location |
Behavior |
| kotaemon/loaders/paddleocr_loader/adapter.py |
_clean_table_html() only strips wrapper; no sanitization |
| ktem/utils/render.py |
Render.table() runs markdown.markdown(); raw HTML in input is passed through |
| ktem/index/file/ui.py |
Table chunks rendered via Render.table(doc.text) into gr.HTML |
| ktem/reasoning/rewoo.py (and similar) |
table_origin concatenated into evidence HTML |
Risk
Example OCR / malicious content:
<table><tr><td><script>alert(document.domain)</script></td></tr></table>
or <img src=x onerror=...> inside a cell → can execute in the browser when evidence/chunks are rendered.
PaddleOCR table blocks are stored as raw HTML in table_content / Document.text and metadata["table_origin"]. That HTML is later shown in the UI without sanitization (Markdown passthrough + gr.HTML), and embedded in reasoning evidence as raw HTML. Because OCR output can contain arbitrary strings (including HTML/script), this is a potential stored XSS when viewing chunks or evidence
Affected code
Risk
Example OCR / malicious content:
or
<img src=x onerror=...>inside a cell → can execute in the browser when evidence/chunks are rendered.