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
CWE-79 (Improper Neutralization of Input During Web Page Generation), CWE-80 (Improper Neutralization of Script-Related HTML Tags in a Web Page)
Affected versions
All versions prior to 2.3.1
Fixed in
2.3.1
Summary
A stored cross-site scripting (XSS) vulnerability in Grimmory's browser-based EPUB reader allows an attacker to embed arbitrary JavaScript in a crafted EPUB file. When a victim opens the book, the script executes in their browser with full access to the Grimmory application's session context. This can enable session token theft and account takeover, including administrative access if an administrator opens the affected book.
Description
EPUB files are ZIP archives containing HTML, and can include <script> tags with executable JavaScript. Grimmory renders EPUB content using foliate-js, embedded in an iframe. The iframe is configured with the sandbox attributes allow-scripts and allow-same-origin.
When both attributes are present simultaneously, JavaScript executing inside the iframe can access the parent frame's DOM and localStorage freely, because allow-same-origin removes the origin-based isolation that would otherwise make allow-scripts safe to use. This nullifies the sandbox's intended protection for any content served from the same origin as the parent application.
An attacker who has permission to upload books can embed malicious JavaScript in an EPUB file and upload it to any library they have access to. Any user who subsequently opens the book will have that script execute silently in their browser, with access to Grimmory's session data.
Note
The misconfiguration is in Grimmory's embedding of foliate-js, not in foliate-js itself.
Attack Scenarios
Session token theft and account takeover. The malicious script reads the session token from localStorage and sends it to an attacker-controlled endpoint. The attacker uses the stolen token to access the victim's account. If the victim is an administrator, this provides full administrative access to the instance.
Authenticated actions on behalf of the victim. Without exfiltrating a token, the script can make authenticated API requests to Grimmory directly from the victim's browser, performing any action the victim is permitted to take.
Distribution via third-party sources. A malicious EPUB does not need to be crafted by someone with an account on the target instance. A book could be prepared and made available through public EPUB distribution channels. A user who downloads it from a third party and uploads it to their Grimmory instance would unknowingly introduce the payload, with no indication that anything has happened when they read it.
Impact
Session token theft enabling account takeover, including administrator accounts
Ability to perform any action the victim is authorised to perform within Grimmory
Potential service worker registration on the Grimmory origin, which could enable request interception within the browser across future sessions
Remediation
The fix removes allow-scripts from the iframe sandbox, preventing untrusted script execution in the reader context.
Upgrade to 2.3.1 as soon as possible.
If an immediate upgrade is not possible: restrict book upload permissions to trusted users only. This does not address the risk from externally sourced books, but it limits the surface for attacker-uploaded content.
Timeline
Date
Event
March 2026
Grimmory forked from BookLore under AGPL-3.0
March 19, 2026
Vulnerability reported to Grimmory by @acfirthh via GitHub private security disclosure
April 22, 2026
Fix merged and advisory published
Credit
Reported by @acfirthh, who followed coordinated disclosure throughout and re-engaged with the Grimmory project after the original report went unpatched in the upstream codebase. Their detailed technical analysis, proof-of-concept material, and patience across a difficult period for this project are genuinely appreciated.
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Learn more on MITRE.
The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special characters such as <, >, and & that could be interpreted as web-scripting elements when they are sent to a downstream component that processes web pages.
Learn more on MITRE.
CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:LSummary
A stored cross-site scripting (XSS) vulnerability in Grimmory's browser-based EPUB reader allows an attacker to embed arbitrary JavaScript in a crafted EPUB file. When a victim opens the book, the script executes in their browser with full access to the Grimmory application's session context. This can enable session token theft and account takeover, including administrative access if an administrator opens the affected book.
Description
EPUB files are ZIP archives containing HTML, and can include
<script>tags with executable JavaScript. Grimmory renders EPUB content usingfoliate-js, embedded in an iframe. The iframe is configured with the sandbox attributesallow-scriptsandallow-same-origin.When both attributes are present simultaneously, JavaScript executing inside the iframe can access the parent frame's DOM and
localStoragefreely, becauseallow-same-originremoves the origin-based isolation that would otherwise makeallow-scriptssafe to use. This nullifies the sandbox's intended protection for any content served from the same origin as the parent application.An attacker who has permission to upload books can embed malicious JavaScript in an EPUB file and upload it to any library they have access to. Any user who subsequently opens the book will have that script execute silently in their browser, with access to Grimmory's session data.
Note
The misconfiguration is in Grimmory's embedding of
foliate-js, not infoliate-jsitself.Attack Scenarios
Session token theft and account takeover. The malicious script reads the session token from
localStorageand sends it to an attacker-controlled endpoint. The attacker uses the stolen token to access the victim's account. If the victim is an administrator, this provides full administrative access to the instance.Authenticated actions on behalf of the victim. Without exfiltrating a token, the script can make authenticated API requests to Grimmory directly from the victim's browser, performing any action the victim is permitted to take.
Distribution via third-party sources. A malicious EPUB does not need to be crafted by someone with an account on the target instance. A book could be prepared and made available through public EPUB distribution channels. A user who downloads it from a third party and uploads it to their Grimmory instance would unknowingly introduce the payload, with no indication that anything has happened when they read it.
Impact
Remediation
The fix removes
allow-scriptsfrom the iframe sandbox, preventing untrusted script execution in the reader context.Upgrade to 2.3.1 as soon as possible.
If an immediate upgrade is not possible: restrict book upload permissions to trusted users only. This does not address the risk from externally sourced books, but it limits the surface for attacker-uploaded content.
Timeline
Credit
Reported by @acfirthh, who followed coordinated disclosure throughout and re-engaged with the Grimmory project after the original report went unpatched in the upstream codebase. Their detailed technical analysis, proof-of-concept material, and patience across a difficult period for this project are genuinely appreciated.
References