You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Arbitrary Code Execution in Template Formatter via Book Metadata
High
kovidgoyal
published
GHSA-2j4m-2q7x-2c47Jun 26, 2026
Package
calibre
Affected versions
<= 9.9.0
Patched versions
9.10.0
Description
Summary
A malicious EPUB, OPF or PDF file can execute arbitrary Python code when its metadata is read by calibre (e.g. Add books, Edit books). The file embeds a custom column definition with a python: template in calibre:user_metadata, which is passed unsanitized to exec() in the template formatter.
Details
When calibre reads book metadata, read_user_metadata parses custom column definitions via json.loads() and stores them verbatim through set_user_metadata(), including executable template strings, with no validation or sanitization.
CALIBRE_ALLOW_PYTHON_TEMPLATES defaults to '1' (enabled), so compile_python_template() passes the check and continues to exec().
PDF via XMP metadata
For PDF files, calibre reads XMP metadata via pdfinfo, then consolidate_metadata() calls metadata_from_xmp_packet() which parses calibre:custom_metadata the same way:
The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
Learn more on MITRE.
The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes code syntax before using the input in a dynamic evaluation call (e.g. eval).
Learn more on MITRE.
Summary
A malicious EPUB, OPF or PDF file can execute arbitrary Python code when its metadata is read by calibre (e.g. Add books, Edit books). The file embeds a custom column definition with a python: template in
calibre:user_metadata, which is passed unsanitized toexec()in the template formatter.Details
When calibre reads book metadata,
read_user_metadataparses custom column definitions viajson.loads()and stores them verbatim throughset_user_metadata(), including executable template strings, with no validation or sanitization.calibre/src/calibre/ebooks/metadata/opf2.py
Lines 672 to 688 in 636c56b
calibre/src/calibre/ebooks/metadata/xmp.py
Lines 176 to 192 in 636c56b
composite_templateEvaluated immediately on metadata read when a composite custom column has
#value#: null:calibre/src/calibre/ebooks/metadata/book/base.py
Lines 146 to 157 in 636c56b
This reaches
exec()through the call chain:safe_format()→evaluate()→_eval_python_template()→compile_python_template()→exec().calibre/src/calibre/utils/formatter.py
Lines 1879 to 1893 in 636c56b
CALIBRE_ALLOW_PYTHON_TEMPLATESdefaults to'1'(enabled), socompile_python_template()passes the check and continues toexec().PDF via XMP metadata
For PDF files, calibre reads XMP metadata via
pdfinfo, thenconsolidate_metadata()callsmetadata_from_xmp_packet()which parsescalibre:custom_metadatathe same way:calibre/src/calibre/ebooks/metadata/pdf.py
Lines 165 to 167 in 636c56b
PoC
poc.mp4
poc.pyRun
poc.py, then openaaaa.epuboraaaa.pdfin calibre.Impact
Same as the summary above.