Skip to content

Stored XSS in ItemSearchCard.vue via Audiobook Metadata (Search Results on Mobile App)

Moderate
advplyr published GHSA-2433-p93m-xhhg Feb 25, 2026

Package

audiobookshelf

Affected versions

<= 2.11.0

Patched versions

>= 2.12.0
audiobookshelf-app
<= 0.11.0-beta
0.12.0-beta

Description

Summary

A stored cross-site scripting (XSS) vulnerability exists in the Audiobookshelf mobile application that allows arbitrary JavaScript execution through malicious library metadata. Attackers with library modification privileges can execute code in victim users' browsers/WebViews, potentially leading to session hijacking, data exfiltration, and unauthorized access to native device APIs.


Details

  • Affected Component: components/cards/ItemSearchCard.vue
  • Affected Versions: Mobile app v0.11.0-beta and earlier
  • Affected Platforms: Mobile app (Android/iOS via Capacitor)
  • Server Compatibility:
    • Confirmed vulnerable: Server v2.11.0 and earlier
    • Status on later versions: Not exploitable due to API changes, assuming the server is non-malicious

Description:

The ItemSearchCard component uses Vue's v-html directive to render search result highlights without sanitizing metadata. While the component attempts to wrap matching text in <strong> tags, it does not escape the surrounding content from library item metadata.

Vulnerable Code Location:

  • File: components/cards/ItemSearchCard.vue
  • Template: <p v-html="matchHtml" />
computed: {
  matchHtml() {
    // matchText contains raw, unsanitized metadata (title, author, series, etc.)
    var matchSplit = this.matchText.toLowerCase().split(this.search.toLowerCase().trim())

    var html = ''
    // Reconstructs string with <strong> tags but doesn't escape parts
    html += `${firstPart}<strong class="text-warning">${actualWasThere}</strong>`
    // firstPart and remaining parts are not HTML-escaped
    return html
  }
}

Attack Vector:

  1. Attacker with library privileges adds item with malicious metadata (e.g., book title: Book Title<img src=x onerror=alert(localStorage.token||JSON.stringify(window.$nuxt.$store.state.user))>)
  2. Victim searches for text that matches part of the malicious field (e.g., searches for "Book")
  3. Search results render the unsanitized HTML via v-html
  4. XSS payload executes in victim's browser/WebView

Proof of Concept: (tested on local instance of v2.11.0 server and v0.11.0-beta Android APK downloaded from GitHub Releases installed on emulator)

Set the book title of an audiobook to include the exploit: Harmless Book Title<img src=x onerror=alert(localStorage.token||JSON.stringify(window.$nuxt.$store.state.user))>

vuln-2-setup

When the user searches for the book title (e.g. by typing in harm), the XSS triggers. This triggers on the mobile client (and outdated web client v2.11.0 and earlier).

vuln-2-search-mobile vuln-2-xss-triggered-mobile vuln-2-xss-triggered-web

The token has been leaked (and a real attack could involve sending it to an external server for the attacker to use).

Important Note:

Requires server version v2.11.0 or earlier to be exploitable. Newer server versions no longer return the matchText and matchKey fields in search API responses, which prevents the vulnerable code path from executing. However, the vulnerable code still exists in the client and could become exploitable again if:

  • The API is changed to restore these fields
  • The component is used with different data sources
  • Older server versions are still in use

Impact

Severity Justification

CVSS 3.1 Vector: CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:N
CVSS Score: 4.0 (Medium)

  • Attack Vector (AV:N): Network - exploitable remotely
  • Attack Complexity (AC:H): High - primarily only exploitable when an older server version is used
  • Privileges Required (PR:H): High - requires library modification access (but not administrator privileges)
  • User Interaction (UI:R): Required - victim must search
  • Scope (S:C): Changed - escapes sandboxing in WebView
  • Confidentiality (C:L): Low- can steal tokens and session data (including admin user token)
  • Integrity (I:L): Low- can modify app/server state and data (especially if admin user is attacked)
  • Availability (A:N): None - can crash app but limited DoS impact

Real-World Impact

Attackers can execute arbitrary code (ex. steal sensitive data from localStorage, notably access tokens, granting admin access if the admin user is successfully attacked)

Attack Prerequisites

  1. Attacker Requirements:

    • Library management permissions (ability to add/edit library items) AND server v2.11.0 or earlier
    • OR compromised Audiobookshelf server
  2. Victim Requirements:

    • Search for text matching the malicious field (ItemSearchCard, mobile client, server v2.11.0 or earlier required)
  3. Environment:

    • ItemSearchCard: Mobile app v0.11.0-beta or earlier, server v2.11.0 or earlier

Patches

Possible Fixes

Option 1: Use text interpolation and CSS for highlighting:

  <template>
-   <p v-html="matchHtml" />
+   <p>{{ firstPart }}<strong class="text-warning">{{ matchPart }}</strong>{{ lastPart }}</p>
  </template>

Option 2: Sanitize HTML before rendering:

import DOMPurify from 'dompurify'

computed: {
  matchHtml() {
    // ... existing logic ...
    const unsafeHtml = `${firstPart}<strong>${match}</strong>${lastPart}`
    return DOMPurify.sanitize(unsafeHtml, {
      ALLOWED_TAGS: ['strong'],
      ALLOWED_ATTR: ['class']
    })
  }
}

Fixed in advplyr/audiobookshelf-app@b2c2b62

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
High
User interaction
Required
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:N

CVE ID

CVE-2026-27973

Weaknesses

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

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.

Credits