VYPR
Moderate severityNVD Advisory· Published Aug 29, 2019· Updated Aug 5, 2024

CVE-2019-15782

CVE-2019-15782

Description

WebTorrent before 0.107.6 is vulnerable to stored XSS via a malicious torrent title or file name when the HTTP server index page is visited.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

WebTorrent before 0.107.6 is vulnerable to stored XSS via a malicious torrent title or file name when the HTTP server index page is visited.

Vulnerability

Overview

CVE-2019-15782 is a cross-site scripting (XSS) vulnerability in the WebTorrent package for Node.js and the browser, affecting versions prior to 0.107.6. The flaw resides in the HTTP server component: when a user starts the server via createServer() and visits the index page that lists torrent contents, the torrent's title or file names are rendered without proper sanitization. An attacker can craft a torrent with a malicious title or file name containing JavaScript, which executes in the context of the victim's browser when the index page is loaded [1][4].

Exploitation

Prerequisites

Exploitation requires the victim to download a torrent with a specially crafted title or file name)Skip and then start the WebTorrent HTTP server and navigate to its index page. The attacker does not need any authentication or special network position beyond being able to supply the malicious torrent to the victim (e.g., via a public tracker or direct download). The WebTorrent HTTP server only serves data pieces from the torrent, so the attacker's script cannot directly control the torrent client, but it can access the page's DOM and exfiltrate information about the downloaded content [1][4].

Impact

Successful exploitation allows the attacker to execute arbitrary JavaScript in the victim's browser within the origin of the WebTorrent server. This can be used to steal the list of files being downloaded, monitor user activity, or exfiltrate data to an external domain. The impact is limited to the context of the torrent index page; however, it could be combined with other attacks if the victim has other sensitive data accessible from that origin [1][4].

Mitigation

The vulnerability was fixed in WebTorrent version 0.107.6. The fix includes two complementary defenses: HTML-escaping of untrusted torrent metadata (name, path, file names) and adding a strict Content Security Policy (CSP) that denies all scripts, styles, plugins, and frames. Users should upgrade to version 0.107.6 or later. No workarounds are documented, but avoiding the use of the HTTP server index page with untrusted torrents reduces risk [3][4].

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
webtorrentnpm
< 0.107.60.107.6

Affected products

2

Patches

1
7e829b5d52c3

Merge pull request #1714 from webtorrent/fix-server-xss

https://github.com/webtorrent/webtorrentFeross AboukhadijehAug 27, 2019via ghsa
2 files changed · +48 10
  • lib/server.js+47 10 modified
    @@ -1,4 +1,5 @@
     const arrayRemove = require('unordered-array-remove')
    +const escapeHtml = require('escape-html')
     const http = require('http')
     const mime = require('mime')
     const pump = require('pump')
    @@ -78,10 +79,6 @@ function Server (torrent, opts = {}) {
     
         const pathname = new URL(req.url, 'http://example.com').pathname
     
    -    if (pathname === '/favicon.ico') {
    -      return serve404Page()
    -    }
    -
         // Allow cross-origin requests (CORS)
         if (isOriginAllowed(req)) {
           res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
    @@ -90,6 +87,13 @@ function Server (torrent, opts = {}) {
         // Prevent browser mime-type sniffing
         res.setHeader('X-Content-Type-Options', 'nosniff')
     
    +    // Defense-in-depth: Set a strict Content Security Policy to mitigate XSS
    +    res.setHeader('Content-Security-Policy', "base-uri 'none'; default-src 'none'; frame-ancestors 'none'; form-action 'none';")
    +
    +    if (pathname === '/favicon.ico') {
    +      return serve404Page()
    +    }
    +
         // Allow CORS requests to specify arbitrary headers, e.g. 'Range',
         // by responding to the OPTIONS preflight request with the specified
         // origin and requested headers.
    @@ -147,11 +151,26 @@ function Server (torrent, opts = {}) {
           res.statusCode = 200
           res.setHeader('Content-Type', 'text/html')
     
    -      const listHtml = torrent.files.map((file, i) => `<li><a download="${file.name}" href="/${i}/${file.name}">${file.path}</a> (${file.length} bytes)</li>`).join('<br>')
    +      const listHtml = torrent.files
    +        .map((file, i) => (
    +          `<li>
    +            <a
    +              download="${escapeHtml(file.name)}"
    +              href="/${escapeHtml(i)}/${escapeHtml(file.name)}"
    +            >
    +              ${escapeHtml(file.path)}
    +            </a>
    +            (${escapeHtml(file.length)} bytes)
    +          </li>`
    +        ))
    +        .join('<br>')
     
           const html = getPageHTML(
    -        `${torrent.name} - WebTorrent`,
    -        `<h1>${torrent.name}</h1><ol>${listHtml}</ol>`
    +        `${escapeHtml(torrent.name)} - WebTorrent`,
    +        `
    +          <h1>${escapeHtml(torrent.name)}</h1>
    +          <ol>${listHtml}</ol>
    +        `
           )
           res.end(html)
         }
    @@ -160,7 +179,10 @@ function Server (torrent, opts = {}) {
           res.statusCode = 404
           res.setHeader('Content-Type', 'text/html')
     
    -      const html = getPageHTML('404 - Not Found', '<h1>404 - Not Found</h1>')
    +      const html = getPageHTML(
    +        '404 - Not Found',
    +        '<h1>404 - Not Found</h1>'
    +      )
           res.end(html)
         }
     
    @@ -214,16 +236,31 @@ function Server (torrent, opts = {}) {
         function serveMethodNotAllowed () {
           res.statusCode = 405
           res.setHeader('Content-Type', 'text/html')
    -      const html = getPageHTML('405 - Method Not Allowed', '<h1>405 - Method Not Allowed</h1>')
    +      const html = getPageHTML(
    +        '405 - Method Not Allowed',
    +        '<h1>405 - Method Not Allowed</h1>'
    +      )
           res.end(html)
         }
       }
     
       return server
     }
     
    +// NOTE: Arguments must already be HTML-escaped
     function getPageHTML (title, pageHtml) {
    -  return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>${title}</title></head><body>${pageHtml}</body></html>`
    +  return `
    +    <!DOCTYPE html>
    +    <html lang="en">
    +      <head>
    +        <meta charset="utf-8">
    +        <title>${title}</title>
    +      </head>
    +      <body>
    +        ${pageHtml}
    +      </body>
    +    </html>
    +  `
     }
     
     // From https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
    
  • package.json+1 0 modified
    @@ -42,6 +42,7 @@
         "create-torrent": "^4.0.0",
         "debug": "^4.1.0",
         "end-of-stream": "^1.1.0",
    +    "escape-html": "^1.0.3",
         "fs-chunk-store": "^2.0.0",
         "http-node": "github:feross/http-node#cddd2872f0020ecf5016f326cf5e58c965eef52a",
         "immediate-chunk-store": "^2.0.0",
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.