---
id: CVE-2026-115897
aliases:
  - GHSA-m5mm-p8h7-m29v
title: >-
  Serialize JavaScript: Cross-site scripting (XSS) via unescaped </script at the
  end of a serialized function body
summary: >-
  Serialize JavaScript: Cross-site scripting (XSS) via unescaped </script at the
  end of a serialized function body
severity: low
cvss: 2.1
cwe:
  - CWE-79
vendor: serialize-javascript
product: serialize-javascript
ecosystem: npm
affected:
  - serialize-javascript < 7.1.3
patched:
  - serialize-javascript 7.1.3
published: '2026-10-23'
updated: '2026-10-23'
sourceUpdated: '2026-10-23T22:09:53Z'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-m5mm-p8h7-m29v'
references:
  - url: >-
      https://github.com/yahoo/serialize-javascript/security/advisories/GHSA-m5mm-p8h7-m29v
  - url: 'https://github.com/yahoo/serialize-javascript/pull/235'
  - url: >-
      https://github.com/yahoo/serialize-javascript/commit/2864b3c6260a3bfd52d2db3e70d1a079de108a61
  - url: 'https://github.com/yahoo/serialize-javascript/releases/tag/v7.1.3'
  - url: 'https://github.com/advisories/GHSA-m5mm-p8h7-m29v'
tags:
  - ghsa
  - npm
  - cve.org
cvssVector: 'CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N'
cvssSource: cna
ingestedAt: '2026-10-24T00:46:53.667Z'
---

## Overview

### Impact

`serialize-javascript` escapes its output so it is safe to embed inside a
`<script>` element. Before 7.1.3 that guarantee did not hold for a **function
value whose source ends in a bare `</script`**.

Each function body is escaped on its own, and a bare `</script` was only
neutralized when followed — within the same body — by a character the HTML
tokenizer treats as ending the tag name (TAB, LF, FF, CR, SPACE, `/` or `>`).
A body ending exactly at `</script` has no following character, so it was
emitted unescaped. The delimiter is then supplied by the surrounding output
(for example the newline the `space` option emits after the value), and a
later serialized value can supply the closing `>` followed by markup:

```js
const serialize = require('serialize-javascript');
function f() {} f.toString = () => 'function f(){ return 1 }//</script';
function g() {} g.toString = () => 'function g(x){ return x } > <img src=x onerror=alert(1)>';
serialize({ a: { f }, g }, { space: 2 });
// {
//   "a": {
//     "f": function f(){ return 1 }//</script
//   },
//   "g": function g(x){ return x } > <img src=x onerror=alert(1)>
// }
```

Embedded in a `<script>` element, the script ends at the injected tag and the
`<img>` becomes a live element in the page.

Exploitation requires an attacker to control the **source text** of a
serialized function, in practice through a spoofed `toString()`. Real
functions always end in `}`, so ordinary function values are not affected,
and non-function values (including strings containing `</script`) are
escaped correctly.

### Patches

Fixed in **7.1.3** (#235). The bare `</script` form is now also matched at
the end of the function body, so it is escaped regardless of what follows it
in the output.

### Workarounds

Upgrade to **7.1.3**. If you cannot upgrade, do not serialize function values
whose source text (or `toString()`) can be influenced by an attacker.

### Credits

Reported by **ha_kr25** via the Yahoo bug bounty program.

## Affected packages

- `serialize-javascript < 7.1.3`

## Remediation

Upgrade to a patched release:

- `serialize-javascript 7.1.3`
