VYPR
Critical severity9.8OSV Advisory· Published Dec 9, 2025· Updated Apr 15, 2026

CVE-2025-67489

CVE-2025-67489

Description

@vitejs/plugin-rs provides React Server Components (RSC) support for Vite. Versions 0.5.5 and below are vulnerable to arbitrary remote code execution on the development server through unsafe dynamic imports in server function APIs (loadServerAction, decodeReply, decodeAction) when integrated into RSC applications that expose server function endpoints. Attackers with network access to the development server can read/modify files, exfiltrate sensitive data (source code, environment variables, credentials), or pivot to other internal services. While this affects development servers only, the risk increases when using vite --host to expose the server on all network interfaces. This issue is fixed in version 0.5.6.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@vitejs/plugin-rscnpm
< 0.5.60.5.6

Affected products

1

Patches

1
fe634b58210d

fix(rsc): validate reference id on dev (#1010)

https://github.com/vitejs/vite-plugin-reactHiroshi OgawaDec 8, 2025via ghsa
5 files changed · +112 2
  • packages/plugin-rsc/e2e/starter.test.ts+45 0 modified
    @@ -7,6 +7,51 @@ import { x } from 'tinyexec'
     test.describe('dev-default', () => {
       const f = useFixture({ root: 'examples/starter', mode: 'dev' })
       defineStarterTest(f)
    +
    +  test('validate reference 1', async () => {
    +    const requestUrl = f.url('_.rsc')
    +    const formData = new FormData()
    +    const payload = {
    +      '0': [1, '$F1'],
    +      '1': { id: '__invalid_reference__# ' },
    +    }
    +    for (const [k, v] of Object.entries(payload)) {
    +      formData.append(k, JSON.stringify(v))
    +    }
    +    const response = await fetch(requestUrl, {
    +      method: 'POST',
    +      body: formData,
    +      headers: {
    +        'x-rsc-action': '/src/action.tsx#updateServerCounter',
    +      },
    +    })
    +    expect(f.proc().stderr()).toContain(
    +      `invalid server reference '__invalid_reference__`,
    +    )
    +    expect(response.status).toBe(500)
    +  })
    +
    +  test('validate reference 2', async () => {
    +    const requestUrl = f.url('_.rsc')
    +    const formData = new FormData()
    +    const payload = {
    +      '0': [1],
    +    }
    +    for (const [k, v] of Object.entries(payload)) {
    +      formData.append(k, JSON.stringify(v))
    +    }
    +    const response = await fetch(requestUrl, {
    +      method: 'POST',
    +      body: formData,
    +      headers: {
    +        'x-rsc-action': `__invalid_reference__# `,
    +      },
    +    })
    +    expect(f.proc().stderr()).toContain(
    +      `invalid server reference '__invalid_reference__'`,
    +    )
    +    expect(response.status).toBe(500)
    +  })
     })
     
     test.describe('build-default', () => {
    
  • packages/plugin-rsc/src/plugins/shared.ts+20 0 modified
    @@ -27,3 +27,23 @@ export function parseIdQuery(id: string): {
       const query = Object.fromEntries(new URLSearchParams(rawQuery))
       return { filename, query }
     }
    +
    +export type ReferenceValidationVirtual = {
    +  id: string
    +  type: 'server' | 'client'
    +}
    +
    +export function toReferenceValidationVirtual({
    +  id,
    +  type,
    +}: ReferenceValidationVirtual) {
    +  return `virtual:vite-rsc/reference-validation?type=${type}&id=${encodeURIComponent(id)}&lang.js`
    +}
    +
    +export function parseReferenceValidationVirtual(
    +  id: string,
    +): ReferenceValidationVirtual | undefined {
    +  if (id.startsWith('\0virtual:vite-rsc/reference-validation?')) {
    +    return parseIdQuery(id).query as any
    +  }
    +}
    
  • packages/plugin-rsc/src/plugin.ts+37 1 modified
    @@ -54,7 +54,12 @@ import { createDebug } from '@hiogawa/utils'
     import { scanBuildStripPlugin } from './plugins/scan'
     import { validateImportPlugin } from './plugins/validate-import'
     import { vitePluginFindSourceMapURL } from './plugins/find-source-map-url'
    -import { parseCssVirtual, toCssVirtual, parseIdQuery } from './plugins/shared'
    +import {
    +  parseCssVirtual,
    +  toCssVirtual,
    +  parseIdQuery,
    +  parseReferenceValidationVirtual,
    +} from './plugins/shared'
     import { stripLiteral } from 'strip-literal'
     
     const isRolldownVite = 'rolldownVersion' in vite
    @@ -261,6 +266,37 @@ export function vitePluginRscMinimal(
         ...vitePluginUseClient(rscPluginOptions, manager),
         ...vitePluginUseServer(rscPluginOptions, manager),
         ...vitePluginDefineEncryptionKey(rscPluginOptions),
    +    {
    +      name: 'rsc:reference-validation',
    +      apply: 'serve',
    +      load: {
    +        handler(id, _options) {
    +          if (id.startsWith('\0virtual:vite-rsc/reference-validation?')) {
    +            const parsed = parseReferenceValidationVirtual(id)
    +            assert(parsed)
    +            if (parsed.type === 'client') {
    +              const meta = Object.values(manager.clientReferenceMetaMap).find(
    +                (meta) => meta.referenceKey === parsed.id,
    +              )
    +              if (meta) {
    +                return `export {}`
    +              }
    +            }
    +            if (parsed.type === 'server') {
    +              const meta = Object.values(manager.serverReferenceMetaMap).find(
    +                (meta) => meta.referenceKey === parsed.id,
    +              )
    +              if (meta) {
    +                return `export {}`
    +              }
    +            }
    +            this.error(
    +              `[vite-rsc] invalid ${parsed.type} reference '${parsed.id}'`,
    +            )
    +          }
    +        },
    +      },
    +    },
         scanBuildStripPlugin({ manager }),
       ]
     }
    
  • packages/plugin-rsc/src/rsc.tsx+5 0 modified
    @@ -1,5 +1,6 @@
     import serverReferences from 'virtual:vite-rsc/server-references'
     import { setRequireModule } from './core/rsc'
    +import { toReferenceValidationVirtual } from './plugins/shared'
     
     export {
       createClientManifest,
    @@ -20,6 +21,10 @@ function initialize(): void {
       setRequireModule({
         load: async (id) => {
           if (!import.meta.env.__vite_rsc_build__) {
    +        await import(
    +          /* @vite-ignore */ '/@id/__x00__' +
    +            toReferenceValidationVirtual({ id, type: 'server' })
    +        )
             return import(/* @vite-ignore */ id)
           } else {
             const import_ = serverReferences[id]
    
  • packages/plugin-rsc/src/ssr.tsx+5 1 modified
    @@ -3,7 +3,7 @@ import * as clientReferences from 'virtual:vite-rsc/client-references'
     import * as ReactDOM from 'react-dom'
     import { setRequireModule } from './core/ssr'
     import type { ResolvedAssetDeps } from './plugin'
    -import { toCssVirtual } from './plugins/shared'
    +import { toCssVirtual, toReferenceValidationVirtual } from './plugins/shared'
     
     export { createServerConsumerManifest } from './core/ssr'
     
    @@ -15,6 +15,10 @@ function initialize(): void {
       setRequireModule({
         load: async (id) => {
           if (!import.meta.env.__vite_rsc_build__) {
    +        await import(
    +          /* @vite-ignore */ '/@id/__x00__' +
    +            toReferenceValidationVirtual({ id, type: 'client' })
    +        )
             const mod = await import(/* @vite-ignore */ id)
             const modCss = await import(
               /* @vite-ignore */ '/@id/__x00__' + toCssVirtual({ id, type: 'ssr' })
    

Vulnerability mechanics

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

References

4

News mentions

0

No linked articles in our index yet.