---
id: "CVE-2026-115897"
kind: "vulnerability"
aliases: ["CVE-2026-115897", "GHSA-m5mm-p8h7-m29v"]
title: "Serialize JavaScript: Cross-site scripting (XSS) via unescaped </script at the end of a serialized function body"
severity: "low"
cvss: 2.1
epss: 0.00394
exploited: false
status: "open"
category: "package"
products: [{"name": "serialize-javascript", "fixed": ["7.1.3"], "affected": "< 7.1.3", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["cwe-79", "npm", "package", "serialize-javascript", "server-rendered-html", "web"]
not_affected_if: ["data-only-serialization", "no-function-values"]
published_at: "2026-10-23T22:09:52+00:00"
first_seen_at: "2026-10-23T22:15:56+00:00"
updated_at: "2026-10-25T12:38:49+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-m5mm-p8h7-m29v", "first_seen_at": "2026-10-23T22:15:56+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-115897", "first_seen_at": "2026-10-23T22:29:04+00:00"}, {"source": "epss", "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-115897", "first_seen_at": "2026-10-25T12:38:49+00:00"}]
---

# Serialize JavaScript: Cross-site scripting (XSS) via unescaped </script at the end of a serialized function body

serialize-javascript fails to escape a bare closing script tag at the end of a serialized function's source text before version 7.1.3. An attacker who controls a function's toString output can break out of a script element and inject HTML such as an img tag that runs JavaScript in the page.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:serialize-javascript affected < 7.1.3 fixed 7.1.3

## How to check

- Run `npm ls serialize-javascript` in each project to find the installed version.
- Check lockfiles (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`) for `serialize-javascript` below `7.1.3`.
- Check whether the app serializes function values into HTML with this package and whether any function's toString can be influenced by user input.

## Fix

- Upgrade `serialize-javascript` to `7.1.3` or later.
- If upgrading is not possible, stop serializing function values whose source text or toString can be influenced by an attacker.

## Timeline

- 2026-10-23T22:15:56+00:00 ghsa https://github.com/advisories/GHSA-m5mm-p8h7-m29v
- 2026-10-23T22:29:04+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-115897
- 2026-10-25T12:38:49+00:00 epss https://api.first.org/data/v1/epss?cve=CVE-2026-115897

## From the sources

### 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.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
