VYPR
Medium severityOSV Advisory· Published Feb 14, 2025· Updated Apr 15, 2026

CVE-2025-25304

CVE-2025-25304

Description

Vega is a visualization grammar, a declarative format for creating, saving, and sharing interactive visualization designs. Prior to version 5.26.0 of vega and 5.4.2 of vega-selections, the vlSelectionTuples function can be used to call JavaScript functions, leading to cross-site scripting.vlSelectionTuples calls multiple functions that can be controlled by an attacker, including one call with an attacker-controlled argument. This can be used to call Function() with arbitrary JavaScript and the resulting function can be called with vlSelectionTuples or using a type coercion to call toString or valueOf. Version 5.26.0 of vega and 5.4.2 of vega-selections fix this issue.

AI Insight

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

Vega and vega-selections prior to 5.26.0/5.4.2 contain an XSS vulnerability where the vlSelectionTuples function can call arbitrary JavaScript via attacker-controlled arguments.

Vulnerability

Overview

CVE-2025-25304 is a cross-site scripting (XSS) vulnerability in Vega, a declarative visualization grammar, and the separate vega-selections package. The flaw resides in the vlSelectionTuples function, which is used to process selection interactions. An attacker can control arguments passed to this function, triggering execution of arbitrary JavaScript. Specifically, vlSelectionTuples calls multiple functions that can be influenced by an attacker, including one call with an attacker-controlled argument. This can be exploited to invoke Function() with arbitrary code, and the resulting function can then be called via vlSelectionTuples or through type coercion to toString or valueOf. [1][4]

Exploitation

Method

To exploit the vulnerability, an attacker crafts a malicious Vega specification that passes a specially crafted object to vlSelectionTuples. For example, a call like vlSelectionTuples([{datum:}], {fields:[{getter:}]}) allows the attacker to control the getter function. By setting getter to [].at.constructor (i.e., Function), the attacker can execute arbitrary JavaScript. The provided proof-of-concept uses a signal with an init expression that coerces values through valueOf, leading to code execution. No authentication is required if the attacker can supply or modify a Vega specification. [2][4]

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the user's browser when the visualization is rendered. This can lead to session hijacking, data exfiltration, or defacement. The vulnerability affects all Vega and vega-selections versions before the fixes.

Mitigation

The Vega team patched this issue in Vega version 5.26.0 and vega-selections version 5.4.2. Users should update to these or later versions immediately. There are no known workarounds. The vulnerability is not yet listed in CISA's Known Exploited Vulnerabilities catalog, but prompt patching is recommended. [3][4]

AI Insight generated on May 20, 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
veganpm
< 5.26.05.26.0
vega-selectionsnpm
< 5.4.25.4.2

Affected products

4
  • Vega/VegaOSV2 versions
    v1.0.0, v1.1.0, v1.2.0, …+ 1 more
    • (no CPE)range: v1.0.0, v1.1.0, v1.2.0, …
    • (no CPE)range: <5.26.0
  • ghsa-coords2 versions
    < 5.26.0+ 1 more
    • (no CPE)range: < 5.26.0
    • (no CPE)range: < 5.4.2

Patches

2
9fb9ea07e279

Merge pull request from GHSA-mp7w-mhcv-673j

https://github.com/vega/vegaArvind SatyanarayanJun 30, 2023via ghsa
5 files changed · +19 9
  • packages/vega-selections/src/selectionResolve.js+1 1 modified
    @@ -1,6 +1,6 @@
     import {intersection, union} from 'd3-array';
     import {array, toNumber} from 'vega-util';
    -import {$selectionId, And, Or, SelectionId, Union, VlMulti, VlPoint} from './constants';
    +import {$selectionId, And, Or, SelectionId, Union, VlMulti, VlPoint} from './util';
     
     /**
      * Resolves selection for use as a scale domain or reads via the API.
    
  • packages/vega-selections/src/selectionTest.js+3 4 modified
    @@ -1,6 +1,6 @@
     import {bisector} from 'd3-array';
    -import {$selectionId, Intersect} from './constants';
    -import {field, inrange, isArray, isDate, toNumber} from 'vega-util';
    +import {inrange, isArray, isDate, toNumber} from 'vega-util';
    +import {$selectionId, Intersect, getter} from './util';
     
     const TYPE_ENUM = 'E',
         TYPE_RANGE_INC = 'R',
    @@ -18,8 +18,7 @@ function testPoint(datum, entry) {
     
       for (; i<n; ++i) {
         f = fields[i];
    -    f.getter = field.getter || field(f.field);
    -    dval = f.getter(datum);
    +    dval = getter(f)(datum);
     
         if (isDate(dval)) dval = toNumber(dval);
         if (isDate(values[i])) values[i] = toNumber(values[i]);
    
  • packages/vega-selections/src/selectionTuples.js+3 3 modified
    @@ -1,5 +1,5 @@
    -import {extend, field} from 'vega-util';
    -import {$selectionId, SelectionId} from './constants';
    +import {extend} from 'vega-util';
    +import {$selectionId, SelectionId, getter} from './util';
     
     /**
      * Maps an array of scene graph items to an array of selection tuples.
    @@ -11,7 +11,7 @@ import {$selectionId, SelectionId} from './constants';
     export function selectionTuples(array, base) {
       return array.map(x => extend(
         base.fields ? {
    -      values: base.fields.map(f => (f.getter || (f.getter = field(f.field)))(x.datum))
    +      values: base.fields.map(f => getter(f)(x.datum))
         } : {
           [SelectionId]: $selectionId(x.datum)
         }, base));
    
  • packages/vega-selections/src/selectionVisitor.js+1 1 modified
    @@ -1,6 +1,6 @@
    -import {Intersect} from './constants';
     import {Literal} from 'vega-expression';
     import {error, hasOwnProperty, peek} from 'vega-util';
    +import {Intersect} from './util';
     
     const DataPrefix = ':',
           IndexPrefix = '@';
    
  • packages/vega-selections/src/util.js+11 0 renamed
    @@ -1,5 +1,16 @@
     import {field} from 'vega-util';
     
    +// Registers vega-util field accessors to protect against XSS attacks
    +const SELECTION_GETTER = Symbol('vega_selection_getter');
    +export function getter(f) {
    +  if (!f.getter || !f.getter[SELECTION_GETTER]) {
    +    f.getter = field(f.field);
    +    f.getter[SELECTION_GETTER] = true;
    +  }
    +
    +  return f.getter;
    +}
    +
     export const Intersect = 'intersect';
     export const Union = 'union';
     export const VlMulti = 'vlMulti';
    

Vulnerability mechanics

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

References

5

News mentions

0

No linked articles in our index yet.