CVE-2024-35236 (published 2024-05-27T17:15Z)

Audiobookshelf is a self-hosted audiobook and podcast server. Prior to version 2.10.0, opening an ebook with malicious scripts inside leads to code execution inside the browsing context. Attacking a user with high privileges (upload, creation of libraries) can lead to remote code execution (RCE) in the worst case. This was tested on version 2.9.0 on Windows, but an arbitrary file write is powerful enough as is and should easily lead to RCE on Linux, too. Version 2.10.0 contains a patch for the vulnerability.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/advplyr/audiobookshelf
commit_details: repo_url: https://github.com/advplyr/audiobookshelf
author: advplyr
author_date: 2024-05-26 16:01:08-05:00
msg: Update:Disable epubs from running scripts by default, add library setting to enable it GHSA-7j99-76cj-q9pg
repository: repo_url: https://github.com/advplyr/audiobookshelf
repo_name: advplyr/audiobookshelf
description: Self-hosted audiobook and podcast server
repo_language: JavaScript
owner: advplyr
file_changes: filename: LibrarySettings.vue
change_type: ModificationType.MODIFY
diff: @@ -60,6 +60,17 @@
         </ui-tooltip>
       </div>
     </div>
+    <div v-if="isBookLibrary" class="py-3">
+      <div class="flex items-center">
+        <ui-toggle-switch v-model="epubsAllowScriptedContent" @input="formUpdated" />
+        <ui-tooltip :text="$strings.LabelSettingsEpubsAllowScriptedContentHelp">
+          <p class="pl-4 text-base">
+            {{ $strings.LabelSettingsEpubsAllowScriptedContent }}
+            <span class="material-icons icon-text text-sm">info_outlined</span>
+          </p>
+        </ui-tooltip>
+      </div>
+    </div>
     <div v-if="isPodcastLibrary" class="py-3">
       <ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
     </div>
@@ -83,6 +94,7 @@ export default {
       skipMatchingMediaWithAsin: false,
       skipMatchingMediaWithIsbn: false,
       audiobooksOnly: false,
+      epubsAllowScriptedContent: false,
       hideSingleBookSeries: false,
       onlyShowLaterBooksInContinueSeries: false,
       podcastSearchRegion: 'us'
@@ -118,6 +130,7 @@ export default {
           skipMatchingMediaWithAsin: !!this.skipMatchingMediaWithAsin,
           skipMatchingMediaWithIsbn: !!this.skipMatchingMediaWithIsbn,
           audiobooksOnly: !!this.audiobooksOnly,
+          epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
           hideSingleBookSeries: !!this.hideSingleBookSeries,
           onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries,
           podcastSearchRegion: this.podcastSearchRegion
@@ -133,6 +146,7 @@ export default {
       this.skipMatchingMediaWithAsin = !!this.librarySettings.skipMatchingMediaWithAsin
       this.skipMatchingMediaWithIsbn = !!this.librarySettings.skipMatchingMediaWithIsbn
       this.audiobooksOnly = !!this.librarySettings.audiobooksOnly
+      this.epubsAllowScriptedContent = !!this.librarySettings.epubsAllowScriptedContent
       this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries
       this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
       this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us'
@@ -142,4 +156,4 @@ export default {
     this.init()
   }
 }
-</script>
\ No newline at end of file
+</script>

programming_language: HTML
filename: EpubReader.vue
change_type: ModificationType.MODIFY
diff: @@ -63,6 +63,9 @@ export default {
     libraryItemId() {
       return this.libraryItem?.id
     },
+    allowScriptedContent() {
+      return this.$store.getters['libraries/getLibraryEpubsAllowScriptedContent']
+    },
     hasPrev() {
       return !this.rendition?.location?.atStart
     },
@@ -316,7 +319,7 @@ export default {
       reader.rendition = reader.book.renderTo('viewer', {
         width: this.readerWidth,
         height: this.readerHeight * 0.8,
-        allowScriptedContent: true,
+        allowScriptedContent: this.allowScriptedContent,
         spread: 'auto',
         snap: true,
         manager: 'continuous',

programming_language: JavaScript
filename: libraries.js
change_type: ModificationType.MODIFY
diff: @@ -16,8 +16,8 @@ export const state = () => ({
 })
 
 export const getters = {
-  getCurrentLibrary: state => {
-    return state.libraries.find(lib => lib.id === state.currentLibraryId)
+  getCurrentLibrary: (state) => {
+    return state.libraries.find((lib) => lib.id === state.currentLibraryId)
   },
   getCurrentLibraryName: (state, getters) => {
     var currentLibrary = getters.getCurrentLibrary
@@ -28,11 +28,11 @@ export const getters = {
     if (!getters.getCurrentLibrary) return null
     return getters.getCurrentLibrary.mediaType
   },
-  getSortedLibraries: state => () => {
-    return state.libraries.map(lib => ({ ...lib })).sort((a, b) => a.displayOrder - b.displayOrder)
+  getSortedLibraries: (state) => () => {
+    return state.libraries.map((lib) => ({ ...lib })).sort((a, b) => a.displayOrder - b.displayOrder)
   },
-  getLibraryProvider: state => libraryId => {
-    var library = state.libraries.find(l => l.id === libraryId)
+  getLibraryProvider: (state) => (libraryId) => {
+    var library = state.libraries.find((l) => l.id === libraryId)
     if (!library) return null
     return library.provider
   },
@@ -60,11 +60,14 @@ export const getters = {
   getLibraryIsAudiobooksOnly: (state, getters) => {
     return !!getters.getCurrentLibrarySettings?.audiobooksOnly
   },
-  getCollection: state => id => {
-    return state.collections.find(c => c.id === id)
+  getLibraryEpubsAllowScriptedContent: (state, getters) => {
+    return !!getters.getCurrentLibrarySettings?.epubsAllowScriptedContent
   },
-  getPlaylist: state => id => {
-    return state.userPlaylists.find(p => p.id === id)
+  getCollection: (state) => (id) => {
+    return state.collections.find((c) => c.id === id)
+  },
+  getPlaylist: (state) => (id) => {
+    return state.userPlaylists.find((p) => p.id === id)
   }
 }
 
@@ -75,7 +78,8 @@ export const actions = {
   loadFolders({ state, commit }) {
     if (state.folders.length) {
       const lastCheck = Date.now() - state.folderLastUpdate
-      if (lastCheck < 1000 * 5) { // 5 seconds
+      if (lastCheck < 1000 * 5) {
+        // 5 seconds
         // Folders up to date
         return state.folders
       }
@@ -204,7 +208,7 @@ export const mutations = {
     })
   },
   addUpdate(state, library) {
-    var index = state.libraries.findIndex(a => a.id === library.id)
+    var index = state.libraries.findIndex((a) => a.id === library.id)
     if (index >= 0) {
       state.libraries.splice(index, 1, library)
     } else {
@@ -216,19 +220,19 @@ export const mutations = {
     })
   },
   remove(state, library) {
-    state.libraries = state.libraries.filter(a => a.id !== library.id)
+    state.libraries = state.libraries.filter((a) => a.id !== library.id)
 
     state.listeners.forEach((listener) => {
       listener.meth()
     })
   },
   addListener(state, listener) {
-    var index = state.listeners.findIndex(l => l.id === listener.id)
+    var index = state.listeners.findIndex((l) => l.id === listener.id)
     if (index >= 0) state.listeners.splice(index, 1, listener)
     else state.listeners.push(listener)
   },
   removeListener(state, listenerId) {
-    state.listeners = state.listeners.filter(l => l.id !== listenerId)
+    state.listeners = state.listeners.filter((l) => l.id !== listenerId)
   },
   setLibraryFilterData(state, filterData) {
     state.filterData = filterData
@@ -238,7 +242,7 @@ export const mutations = {
   },
   removeSeriesFromFilterData(state, seriesId) {
     if (!seriesId || !state.filterData) return
-    state.filterData.series = state.filterData.series.filter(se => se.id !== seriesId)
+    state.filterData.series = state.filterData.series.filter((se) => se.id !== seriesId)
   },
   updateFilterDataWithItem(state, libraryItem) {
     if (!libraryItem || !state.filterData) return
@@ -260,12 +264,12 @@ export const mutations = {
     // Add/update book authors
     if (mediaMetadata.authors?.length) {
       mediaMetadata.authors.forEach((author) => {
-        const indexOf = state.filterData.authors.findIndex(au => au.id === author.id)
+        const indexOf = state.filterData.authors.findIndex((au) => au.id === author.id)
         if (indexOf >= 0) {
           state.filterData.authors.splice(indexOf, 1, author)
         } else {
           state.filterData.authors.push(author)
-          state.filterData.authors.sort((a, b) => (a.name || '').localeCompare((b.name || '')))
+          state.filterData.authors.sort((a, b) => (a.name || '').localeCompare(b.name || ''))
         }
       })
     }
@@ -273,12 +277,12 @@ export const mutations = {
     // Add/update series
     if (mediaMetadata.series?.length) {
       mediaMetadata.series.forEach((series) => {
-        const indexOf = state.filterData.series.findIndex(se => se.id === series.id)
+        const indexOf = state.filterData.series.findIndex((se) => se.id === series.id)
         if (indexOf >= 0) {
           state.filterData.series.splice(indexOf, 1, { id: series.id, name: series.name })
         } else {
           state.filterData.series.push({ id: series.id, name: series.name })
-          state.filterData.series.sort((a, b) => (a.name || '').localeCompare((b.name || '')))
+          state.filterData.series.sort((a, b) => (a.name || '').localeCompare(b.name || ''))
         }
       })
     }
@@ -329,7 +333,7 @@ export const mutations = {
     state.collections = collections
   },
   addUpdateCollection(state, collection) {
-    var index = state.collections.findIndex(c => c.id === collection.id)
+    var index = state.collections.findIndex((c) => c.id === collection.id)
     if (index >= 0) {
       state.collections.splice(index, 1, collection)
     } else {
@@ -337,14 +341,14 @@ export const mutations = {
     }
   },
   removeCollection(state, collection) {
-    state.collections = state.collections.filter(c => c.id !== collection.id)
+    state.collections = state.collections.filter((c) => c.id !== collection.id)
   },
   setUserPlaylists(state, playlists) {
     state.userPlaylists = playlists
     state.numUserPlaylists = playlists.length
   },
   addUpdateUserPlaylist(state, playlist) {
-    const index = state.userPlaylists.findIndex(p => p.id === playlist.id)
+    const index = state.userPlaylists.findIndex((p) => p.id === playlist.id)
     if (index >= 0) {
       state.userPlaylists.splice(index, 1, playlist)
     } else {
@@ -353,10 +357,10 @@ export const mutations = {
     }
   },
   removeUserPlaylist(state, playlist) {
-    state.userPlaylists = state.userPlaylists.filter(p => p.id !== playlist.id)
+    state.userPlaylists = state.userPlaylists.filter((p) => p.id !== playlist.id)
     state.numUserPlaylists = state.userPlaylists.length
   },
   setEReaderDevices(state, ereaderDevices) {
     state.ereaderDevices = ereaderDevices
   }
-}
\ No newline at end of file
+}

programming_language: JavaScript
filename: bg.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Включи наблюдателя",
   "LabelSettingsEnableWatcherForLibrary": "Включи наблюдателя за библиотека",
   "LabelSettingsEnableWatcherHelp": "Включва автоматичното добавяне/обновяване на елементи, когато се открият промени във файловете. *Изисква рестарт на сървъра",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Експериментални Функции",
   "LabelSettingsExperimentalFeaturesHelp": "Функции в разработка, които могат да изискват вашето мнение и помощ за тестване. Кликнете за да отворите дискусия в github.",
   "LabelSettingsFindCovers": "Намери Корици",

programming_language: JavaScript
filename: bn.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "প্রহরী সক্ষম করুন",
   "LabelSettingsEnableWatcherForLibrary": "লাইব্রেরির জন্য ফোল্ডার প্রহরী সক্ষম করুন",
   "LabelSettingsEnableWatcherHelp": "ফাইলের পরিবর্তন শনাক্ত হলে আইটেমগুলির স্বয়ংক্রিয় যোগ/আপডেট সক্ষম করবে। *সার্ভার পুনরায় চালু করতে হবে",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "পরীক্ষামূলক বৈশিষ্ট্য",
   "LabelSettingsExperimentalFeaturesHelp": "ফিচারের বৈশিষ্ট্য যা আপনার প্রতিক্রিয়া ব্যবহার করতে পারে এবং পরীক্ষায় সহায়তা করতে পারে। গিটহাব আলোচনা খুলতে ক্লিক করুন।",
   "LabelSettingsFindCovers": "কভার খুঁজুন",

programming_language: JavaScript
filename: cs.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Povolit sledování",
   "LabelSettingsEnableWatcherForLibrary": "Povolit sledování složky pro knihovnu",
   "LabelSettingsEnableWatcherHelp": "Povoluje automatické přidávání/aktualizaci položek, když jsou zjištěny změny souborů. *Vyžaduje restart serveru",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimentální funkce",
   "LabelSettingsExperimentalFeaturesHelp": "Funkce ve vývoji, které by mohly využít vaši zpětnou vazbu a pomoc s testováním. Kliknutím otevřete diskuzi na githubu.",
   "LabelSettingsFindCovers": "Najít obálky",

programming_language: JavaScript
filename: da.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Aktiver overvågning",
   "LabelSettingsEnableWatcherForLibrary": "Aktiver mappeovervågning for bibliotek",
   "LabelSettingsEnableWatcherHelp": "Aktiverer automatisk tilføjelse/opdatering af elementer, når filændringer registreres. *Kræver servergenstart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Eksperimentelle funktioner",
   "LabelSettingsExperimentalFeaturesHelp": "Funktioner under udvikling, der kunne bruge din feedback og hjælp til test. Klik for at åbne Github-diskussionen.",
   "LabelSettingsFindCovers": "Find omslag",

programming_language: Scala
filename: de.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Überwachung aktivieren",
   "LabelSettingsEnableWatcherForLibrary": "Ordnerüberwachung für die Bibliothek aktivieren",
   "LabelSettingsEnableWatcherHelp": "Aktiviert das automatische Hinzufügen/Aktualisieren von Elementen, wenn Dateiänderungen erkannt werden. *Erfordert einen Server-Neustart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimentelle Funktionen",
   "LabelSettingsExperimentalFeaturesHelp": "Funktionen welche sich in der Entwicklung befinden, benötigen dein Feedback und deine Hilfe beim Testen. Klicke hier, um die Github-Diskussion zu öffnen.",
   "LabelSettingsFindCovers": "Suche Titelbilder",

programming_language: CoffeeScript
filename: en-us.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Enable Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
   "LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimental features",
   "LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
   "LabelSettingsFindCovers": "Find covers",

programming_language: Scala
filename: es.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Habilitar Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Habilitar Watcher para la carpeta de esta biblioteca",
   "LabelSettingsEnableWatcherHelp": "Permite agregar/actualizar elementos automáticamente cuando se detectan cambios en los archivos. *Requiere reiniciar el servidor",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Funciones Experimentales",
   "LabelSettingsExperimentalFeaturesHelp": "Funciones en desarrollo que se beneficiarían de sus comentarios y experiencias de prueba. Haga click aquí para abrir una conversación en Github.",
   "LabelSettingsFindCovers": "Buscar Portadas",

programming_language: Scala
filename: et.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Luba vaatamine",
   "LabelSettingsEnableWatcherForLibrary": "Luba kaustavaatamine raamatukogu jaoks",
   "LabelSettingsEnableWatcherHelp": "Lubab automaatset lisamist/uuendamist, kui tuvastatakse failimuudatused. *Nõuab serveri taaskäivitamist",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Eksperimentaalsed funktsioonid",
   "LabelSettingsExperimentalFeaturesHelp": "Arengus olevad funktsioonid, mis vajavad teie tagasisidet ja abi testimisel. Klõpsake GitHubi arutelu avamiseks.",
   "LabelSettingsFindCovers": "Leia ümbrised",

programming_language: JavaScript
filename: fr.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Activer la veille",
   "LabelSettingsEnableWatcherForLibrary": "Activer la surveillance des dossiers pour la bibliothèque",
   "LabelSettingsEnableWatcherHelp": "Active la mise à jour automatique automatique lorsque des modifications de fichiers sont détectées. * nécessite le redémarrage du serveur",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Fonctionnalités expérimentales",
   "LabelSettingsExperimentalFeaturesHelp": "Fonctionnalités en cours de développement sur lesquelles nous attendons votre retour et expérience. Cliquez pour ouvrir la discussion GitHub.",
   "LabelSettingsFindCovers": "Chercher des couvertures de livre",

programming_language: JavaScript
filename: gu.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Enable Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
   "LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimental features",
   "LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
   "LabelSettingsFindCovers": "Find covers",

programming_language: JavaScript
filename: he.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "הפעל עוקב",
   "LabelSettingsEnableWatcherForLibrary": "הפעל עוקב תיקייה עבור ספרייה",
   "LabelSettingsEnableWatcherHelp": "מאפשר הוספת/עדכון אוטומטי של פריטים כאשר שינויי קבצים זוהים. *דורש איתחול שרת",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "תכונות ניסיוניות",
   "LabelSettingsExperimentalFeaturesHelp": "תכונות בפיתוח שדורשות משובך ובדיקה. לחץ לפתיחת דיון ב-GitHub.",
   "LabelSettingsFindCovers": "מצא כריכות",

programming_language: JavaScript
filename: hi.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Enable Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
   "LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimental features",
   "LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
   "LabelSettingsFindCovers": "Find covers",

programming_language: JavaScript
filename: hr.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Enable Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
   "LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Eksperimentalni features",
   "LabelSettingsExperimentalFeaturesHelp": "Features u razvoju trebaju vaš feedback i pomoć pri testiranju. Klikni da odeš to Github discussionsa.",
   "LabelSettingsFindCovers": "Pronađi covers",

programming_language: JavaScript
filename: hu.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Figyelő engedélyezése",
   "LabelSettingsEnableWatcherForLibrary": "Mappafigyelő engedélyezése a könyvtárban",
   "LabelSettingsEnableWatcherHelp": "Engedélyezi az automatikus elem hozzáadás/frissítés funkciót, amikor fájlváltozásokat észlel. *Szerver újraindítása szükséges",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Kísérleti funkciók",
   "LabelSettingsExperimentalFeaturesHelp": "Fejlesztés alatt álló funkciók, amelyek visszajelzésre és tesztelésre szorulnak. Kattintson a github megbeszélés megnyitásához.",
   "LabelSettingsFindCovers": "Borítók keresése",

programming_language: JavaScript
filename: it.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Abilita Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Abilita il controllo cartelle per la libreria",
   "LabelSettingsEnableWatcherHelp": "Abilita l'aggiunta/aggiornamento automatico degli elementi quando vengono rilevate modifiche ai file. *Richiede il riavvio del Server",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Opzioni Sperimentali",
   "LabelSettingsExperimentalFeaturesHelp": "Funzionalità in fase di sviluppo che potrebbero utilizzare i tuoi feedback e aiutare i test. Fare clic per aprire la discussione github.",
   "LabelSettingsFindCovers": "Trova covers",

programming_language: Scala
filename: lt.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Enable Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
   "LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Eksperimentiniai funkcionalumai",
   "LabelSettingsExperimentalFeaturesHelp": "Funkcijos, kurios yra kuriamos ir laukiami jūsų komentarai. Spustelėkite, kad atidarytumėte „GitHub“ diskusiją.",
   "LabelSettingsFindCovers": "Rasti viršelius",

programming_language: JavaScript
filename: nl.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Watcher inschakelen",
   "LabelSettingsEnableWatcherForLibrary": "Map-watcher voor bibliotheek inschakelen",
   "LabelSettingsEnableWatcherHelp": "Zorgt voor het automatisch toevoegen/bijwerken van onderdelen als bestandswijzigingen worden gedetecteerd. *Vereist herstarten van server",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimentele functies",
   "LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.",
   "LabelSettingsFindCovers": "Zoek covers",

programming_language: JavaScript
filename: no.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Aktiver overvåker",
   "LabelSettingsEnableWatcherForLibrary": "Aktiver mappe overvåker for bibliotek",
   "LabelSettingsEnableWatcherHelp": "Aktiverer automatisk opprettelse/oppdatering av enheter når filendringer er oppdaget. *Krever restart av server*",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Eksperimentelle funksjoner",
   "LabelSettingsExperimentalFeaturesHelp": "Funksjoner under utvikling som kan trenge din tilbakemelding og hjelp med testing. Klikk for å åpne GitHub diskusjon.",
   "LabelSettingsFindCovers": "Finn omslag",

programming_language: JavaScript
filename: pl.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Enable Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
   "LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Funkcje eksperymentalne",
   "LabelSettingsExperimentalFeaturesHelp": "Funkcje w trakcie rozwoju, które mogą zyskanć na Twojej opinii i pomocy w testowaniu. Kliknij, aby otworzyć dyskusję na githubie.",
   "LabelSettingsFindCovers": "Szukanie okładek",

programming_language: JavaScript
filename: pt-br.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Ativar Monitoramento",
   "LabelSettingsEnableWatcherForLibrary": "Ativa o monitoramento de pastas para a biblioteca",
   "LabelSettingsEnableWatcherHelp": "Ativa o acréscimo/atualização de itens quando forem detectadas mudanças no arquivo. *Requer reiniciar o servidor",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Funcionalidade experimentais",
   "LabelSettingsExperimentalFeaturesHelp": "Funcionalidade em desenvolvimento que se beneficiairam dos seus comentários e da sua ajuda para testar. Clique para abrir a discussão no github.",
   "LabelSettingsFindCovers": "Localizar capas",

programming_language: Scala
filename: ru.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Включить отслеживание",
   "LabelSettingsEnableWatcherForLibrary": "Включить отслеживание за папками библиотеки",
   "LabelSettingsEnableWatcherHelp": "Включает автоматическое добавление/обновление элементов при обнаружении изменений файлов. *Требуется перезапуск сервера",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Экспериментальные функции",
   "LabelSettingsExperimentalFeaturesHelp": "Функционал в разработке на который Вы могли бы дать отзыв или помочь в тестировании. Нажмите для открытия обсуждения на github.",
   "LabelSettingsFindCovers": "Найти обложки",

programming_language: JavaScript
filename: sv.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Aktivera Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Aktivera mappbevakning för bibliotek",
   "LabelSettingsEnableWatcherHelp": "Aktiverar automatiskt lägga till/uppdatera objekt när filändringar upptäcks. *Kräver omstart av servern",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Experimentella funktioner",
   "LabelSettingsExperimentalFeaturesHelp": "Funktioner under utveckling som behöver din feedback och hjälp med testning. Klicka för att öppna diskussionen på GitHub.",
   "LabelSettingsFindCovers": "Hitta omslag",

programming_language: JavaScript
filename: uk.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Увімкнути спостерігача",
   "LabelSettingsEnableWatcherForLibrary": "Увімкнути спостерігання тек бібліотеки",
   "LabelSettingsEnableWatcherHelp": "Вмикає автоматичне додавання/оновлення елементів, коли спостерігаються зміни файлів. *Потребує перезавантаження сервера",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Експериментальні функції",
   "LabelSettingsExperimentalFeaturesHelp": "Функції в розробці, які потребують вашого відгуку та допомоги в тестуванні. Натисніть, щоб відкрити обговорення на Github.",
   "LabelSettingsFindCovers": "Пошук обкладинок",

programming_language: JavaScript
filename: vi-vn.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "Bật Watcher",
   "LabelSettingsEnableWatcherForLibrary": "Bật watcher thư mục cho thư viện",
   "LabelSettingsEnableWatcherHelp": "Bật chức năng tự động thêm/cập nhật các mục khi phát hiện thay đổi tập tin. *Yêu cầu khởi động lại máy chủ",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "Tính năng thử nghiệm",
   "LabelSettingsExperimentalFeaturesHelp": "Các tính năng đang phát triển có thể cần phản hồi của bạn và sự giúp đỡ trong thử nghiệm. Nhấp để mở thảo luận trên github.",
   "LabelSettingsFindCovers": "Tìm ảnh bìa",

programming_language: Scala
filename: zh-cn.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "启用监视程序",
   "LabelSettingsEnableWatcherForLibrary": "为库启用文件夹监视程序",
   "LabelSettingsEnableWatcherHelp": "当检测到文件更改时, 启用项目的自动添加/更新. *需要重新启动服务器",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "实验功能",
   "LabelSettingsExperimentalFeaturesHelp": "开发中的功能需要你的反馈并帮助测试. 点击打开 github 讨论.",
   "LabelSettingsFindCovers": "查找封面",

programming_language: JavaScript
filename: zh-tw.json
change_type: ModificationType.MODIFY
diff: @@ -471,6 +471,8 @@
   "LabelSettingsEnableWatcher": "啟用監視程序",
   "LabelSettingsEnableWatcherForLibrary": "為庫啟用資料夾監視程序",
   "LabelSettingsEnableWatcherHelp": "當檢測到檔案更改時, 啟用項目的自動新增/更新. *需要重新啟動伺服器",
+  "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs",
+  "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.",
   "LabelSettingsExperimentalFeatures": "實驗功能",
   "LabelSettingsExperimentalFeaturesHelp": "開發中的功能需要你的反饋並幫助測試. 點擊打開 github 討論.",
   "LabelSettingsFindCovers": "查找封面",

programming_language: JavaScript
filename: LibrarySettings.js
change_type: ModificationType.MODIFY
diff: @@ -8,6 +8,7 @@ class LibrarySettings {
     this.skipMatchingMediaWithIsbn = false
     this.autoScanCronExpression = null
     this.audiobooksOnly = false
+    this.epubsAllowScriptedContent = false
     this.hideSingleBookSeries = false // Do not show series that only have 1 book
     this.onlyShowLaterBooksInContinueSeries = false // Skip showing books that are earlier than the max sequence read
     this.metadataPrecedence = ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
@@ -25,6 +26,7 @@ class LibrarySettings {
     this.skipMatchingMediaWithIsbn = !!settings.skipMatchingMediaWithIsbn
     this.autoScanCronExpression = settings.autoScanCronExpression || null
     this.audiobooksOnly = !!settings.audiobooksOnly
+    this.epubsAllowScriptedContent = !!settings.epubsAllowScriptedContent
     this.hideSingleBookSeries = !!settings.hideSingleBookSeries
     this.onlyShowLaterBooksInContinueSeries = !!settings.onlyShowLaterBooksInContinueSeries
     if (settings.metadataPrecedence) {
@@ -44,6 +46,7 @@ class LibrarySettings {
       skipMatchingMediaWithIsbn: this.skipMatchingMediaWithIsbn,
       autoScanCronExpression: this.autoScanCronExpression,
       audiobooksOnly: this.audiobooksOnly,
+      epubsAllowScriptedContent: this.epubsAllowScriptedContent,
       hideSingleBookSeries: this.hideSingleBookSeries,
       onlyShowLaterBooksInContinueSeries: this.onlyShowLaterBooksInContinueSeries,
       metadataPrecedence: [...this.metadataPrecedence],
@@ -67,4 +70,4 @@ class LibrarySettings {
     return hasUpdates
   }
 }
-module.exports = LibrarySettings
\ No newline at end of file
+module.exports = LibrarySettings

programming_language: JavaScript