VYPR
Medium severityNVD Advisory· Published Nov 29, 2024· Updated Apr 15, 2026

CVE-2024-52810

CVE-2024-52810

Description

@intlify/shared is a shared library for the intlify project. The latest version of @intlify/shared (10.0.4) is vulnerable to Prototype Pollution through the entry function(s) lib.deepCopy. An attacker can supply a payload with Object.prototype setter to introduce or modify properties within the global prototype chain, causing denial of service (DoS) as the minimum consequence. Moreover, the consequences of this vulnerability can escalate to other injection-based attacks, depending on how the library integrates within the application. For instance, if the polluted property propagates to sensitive Node.js APIs (e.g., exec, eval), it could enable an attacker to execute arbitrary commands within the application's context. This issue has been addressed in versions 9.14.2, and 10.0.5. Users are advised to upgrade. There are no known workarounds for this vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@intlify/sharednpm
>= 9.7.0, < 9.14.29.14.2
@intlify/vue-i18n-corenpm
>= 9.7.0, < 9.14.29.14.2
vue-i18nnpm
>= 9.7.0, < 9.14.29.14.2
petite-vue-i18nnpm
>= 10.0.0, < 10.0.510.0.5
@intlify/sharednpm
>= 10.0.0, < 10.0.510.0.5
@intlify/vue-i18n-corenpm
>= 10.0.0, < 10.0.510.0.5
vue-i18nnpm
>= 10.0.0, < 10.0.510.0.5

Patches

3
9f20909ef8c9

Merge commit from fork

https://github.com/intlify/vue-i18nkazuya kawaguchiNov 28, 2024via ghsa
20 files changed · +210 159
  • packages/core-base/src/compilation.ts+3 2 modified
    @@ -4,6 +4,7 @@ import {
       detectHtmlTag
     } from '@intlify/message-compiler'
     import {
    +  create,
       format,
       hasOwn,
       isBoolean,
    @@ -32,10 +33,10 @@ function checkHtmlMessage(source: string, warnHtmlMessage?: boolean): void {
     }
     
     const defaultOnCacheKey = (message: string): string => message
    -let compileCache: unknown = Object.create(null)
    +let compileCache: unknown = create()
     
     export function clearCompileCache(): void {
    -  compileCache = Object.create(null)
    +  compileCache = create()
     }
     
     export function isMessageAST(val: unknown): val is ResourceNode {
    
  • packages/core-base/src/context.ts+11 8 modified
    @@ -2,6 +2,7 @@
     
     import {
       assign,
    +  create,
       isArray,
       isBoolean,
       isFunction,
    @@ -507,23 +508,23 @@ export function createCoreContext<Message = string>(options: any = {}): any {
           : _locale
       const messages = isPlainObject(options.messages)
         ? options.messages
    -    : { [_locale]: {} }
    +    : createResources(_locale)
       const datetimeFormats = !__LITE__
         ? isPlainObject(options.datetimeFormats)
           ? options.datetimeFormats
    -      : { [_locale]: {} }
    -    : { [_locale]: {} }
    +      : createResources(_locale)
    +    : createResources(_locale)
       const numberFormats = !__LITE__
         ? isPlainObject(options.numberFormats)
           ? options.numberFormats
    -      : { [_locale]: {} }
    -    : { [_locale]: {} }
    +      : createResources(_locale)
    +    : createResources(_locale)
       const modifiers = assign(
    -    {},
    -    options.modifiers || {},
    +    create(),
    +    options.modifiers,
         getDefaultLinkedModifiers<Message>()
       )
    -  const pluralRules = options.pluralRules || {}
    +  const pluralRules = options.pluralRules || create()
       const missing = isFunction(options.missing) ? options.missing : null
       const missingWarn =
         isBoolean(options.missingWarn) || isRegExp(options.missingWarn)
    @@ -628,6 +629,8 @@ export function createCoreContext<Message = string>(options: any = {}): any {
       return context
     }
     
    +const createResources = (locale: Locale) => ({ [locale]: create() })
    +
     /** @internal */
     export function isTranslateFallbackWarn(
       fallback: boolean | RegExp,
    
  • packages/core-base/src/datetime.ts+3 2 modified
    @@ -1,5 +1,6 @@
     import {
       assign,
    +  create,
       isBoolean,
       isDate,
       isEmptyObject,
    @@ -322,8 +323,8 @@ export function parseDateTimeArgs(
       ...args: unknown[]
     ): [string, number | Date, DateTimeOptions, Intl.DateTimeFormatOptions] {
       const [arg1, arg2, arg3, arg4] = args
    -  const options = {} as DateTimeOptions
    -  let overrides = {} as Intl.DateTimeFormatOptions
    +  const options = create() as DateTimeOptions
    +  let overrides = create() as Intl.DateTimeFormatOptions
     
       let value: number | Date
       if (isString(arg1)) {
    
  • packages/core-base/src/number.ts+15 14 modified
    @@ -1,31 +1,32 @@
     import {
    -  isString,
    +  assign,
    +  create,
       isBoolean,
    -  isPlainObject,
    -  isNumber,
       isEmptyObject,
    -  assign
    +  isNumber,
    +  isPlainObject,
    +  isString
     } from '@intlify/shared'
     import {
       handleMissing,
       isTranslateFallbackWarn,
    -  NOT_REOSLVED,
    -  MISSING_RESOLVE_VALUE
    +  MISSING_RESOLVE_VALUE,
    +  NOT_REOSLVED
     } from './context'
    -import { CoreWarnCodes, getWarnMessage } from './warnings'
     import { CoreErrorCodes, createCoreError } from './errors'
    -import { Availabilities } from './intl'
     import { getLocale } from './fallbacker'
    +import { Availabilities } from './intl'
    +import { CoreWarnCodes, getWarnMessage } from './warnings'
     
    -import type { Locale, FallbackLocale } from './runtime'
    +import type { CoreContext, CoreInternalContext } from './context'
    +import type { LocaleOptions } from './fallbacker'
    +import type { FallbackLocale, Locale } from './runtime'
     import type {
       NumberFormat,
    -  NumberFormats as NumberFormatsType,
       NumberFormatOptions,
    +  NumberFormats as NumberFormatsType,
       PickupFormatKeys
     } from './types'
    -import type { LocaleOptions } from './fallbacker'
    -import type { CoreContext, CoreInternalContext } from './context'
     
     /**
      *  # number
    @@ -317,8 +318,8 @@ export function parseNumberArgs(
       ...args: unknown[]
     ): [string, number, NumberOptions, Intl.NumberFormatOptions] {
       const [arg1, arg2, arg3, arg4] = args
    -  const options = {} as NumberOptions
    -  let overrides = {} as Intl.NumberFormatOptions
    +  const options = create() as NumberOptions
    +  let overrides = create() as Intl.NumberFormatOptions
     
       if (!isNumber(arg1)) {
         throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT)
    
  • packages/core-base/src/runtime.ts+3 2 modified
    @@ -1,6 +1,7 @@
     import { HelperNameMap } from '@intlify/message-compiler'
     import {
       assign,
    +  create,
       isArray,
       isFunction,
       isNumber,
    @@ -360,7 +361,7 @@ export function createMessageContext<T = string, N = {}>(
       const list = (index: number): unknown => _list[index]
     
       // eslint-disable-next-line @typescript-eslint/no-explicit-any
    -  const _named = options.named || ({} as any)
    +  const _named = options.named || (create() as any)
     
       isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named)
       const named = (key: string): unknown => _named[key]
    @@ -437,7 +438,7 @@ export function createMessageContext<T = string, N = {}>(
         [HelperNameMap.TYPE]: type,
         [HelperNameMap.INTERPOLATE]: interpolate,
         [HelperNameMap.NORMALIZE]: normalize,
    -    [HelperNameMap.VALUES]: assign({}, _list, _named)
    +    [HelperNameMap.VALUES]: assign(create(), _list, _named)
       }
     
       return ctx
    
  • packages/core-base/src/translate.ts+5 4 modified
    @@ -1,5 +1,6 @@
     import {
       assign,
    +  create,
       escapeHtml,
       generateCodeFrame,
       generateFormatCacheKey,
    @@ -677,7 +678,7 @@ export function translate<
         : [
             key,
             locale,
    -        (messages as unknown as LocaleMessages<Message>)[locale] || {}
    +        (messages as unknown as LocaleMessages<Message>)[locale] || create()
           ]
       // NOTE:
       //  Fix to work around `ssrTransfrom` bug in Vite.
    @@ -830,7 +831,7 @@ function resolveMessageFormat<Messages, Message>(
       } = context
       const locales = localeFallbacker(context as any, fallbackLocale, locale) // eslint-disable-line @typescript-eslint/no-explicit-any
     
    -  let message: LocaleMessageValue<Message> = {}
    +  let message: LocaleMessageValue<Message> = create()
       let targetLocale: Locale | undefined
       let format: PathValue = null
       let from: Locale = locale
    @@ -869,7 +870,7 @@ function resolveMessageFormat<Messages, Message>(
         }
     
         message =
    -      (messages as unknown as LocaleMessages<Message>)[targetLocale] || {}
    +      (messages as unknown as LocaleMessages<Message>)[targetLocale] || create()
     
         // for vue-devtools timeline event
         let start: number | null = null
    @@ -1044,7 +1045,7 @@ export function parseTranslateArgs<Message = string>(
       ...args: unknown[]
     ): [Path | MessageFunction<Message> | ResourceNode, TranslateOptions] {
       const [arg1, arg2, arg3] = args
    -  const options = {} as TranslateOptions
    +  const options = create() as TranslateOptions
     
       if (
         !isString(arg1) &&
    
  • packages/message-compiler/src/tokenizer.ts+5 4 modified
    @@ -1,10 +1,10 @@
    -import { createScanner, CHAR_SP as SPACE, CHAR_LF as NEW_LINE } from './scanner'
    +import { CompileErrorCodes, createCompileError } from './errors'
     import { createLocation, createPosition } from './location'
    -import { createCompileError, CompileErrorCodes } from './errors'
    +import { createScanner, CHAR_LF as NEW_LINE, CHAR_SP as SPACE } from './scanner'
     
    -import type { Scanner } from './scanner'
    -import type { SourceLocation, Position } from './location'
    +import type { Position, SourceLocation } from './location'
     import type { TokenizeOptions } from './options'
    +import type { Scanner } from './scanner'
     
     export const enum TokenTypes {
       Text, // 0
    @@ -447,6 +447,7 @@ export function createTokenizer(
       function readText(scnr: Scanner): string {
         let buf = ''
     
    +     
         while (true) {
           const ch = scnr.currentChar()
           if (
    
  • packages/shared/src/messages.ts+5 2 modified
    @@ -1,4 +1,4 @@
    -import { isArray, isObject } from './utils'
    +import { create, isArray, isObject } from './utils'
     
     const isNotObjectOrIsArray = (val: unknown) => !isObject(val) || isArray(val)
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
    @@ -14,10 +14,13 @@ export function deepCopy(src: any, des: any): void {
     
         // using `Object.keys` which skips prototype properties
         Object.keys(src).forEach(key => {
    +      if (key === '__proto__') {
    +        return
    +      }
           // if src[key] is an object/array, set des[key]
           // to empty object/array to prevent setting by reference
           if (isObject(src[key]) && !isObject(des[key])) {
    -        des[key] = Array.isArray(src[key]) ? [] : {}
    +        des[key] = Array.isArray(src[key]) ? [] : create()
           }
     
           if (isNotObjectOrIsArray(des[key]) || isNotObjectOrIsArray(src[key])) {
    
  • packages/shared/src/utils.ts+4 1 modified
    @@ -81,6 +81,9 @@ export const isEmptyObject = (val: unknown): val is boolean =>
     
     export const assign = Object.assign
     
    +const _create = Object.create
    +export const create = (obj: object | null = null): object => _create(obj)
    +
     let _globalThis: any
     export const getGlobalThis = (): any => {
       // prettier-ignore
    @@ -95,7 +98,7 @@ export const getGlobalThis = (): any => {
                 ? window
                 : typeof global !== 'undefined'
                   ? global
    -              : {})
    +              : create())
       )
     }
     
    
  • packages/shared/test/messages.test.ts+31 0 modified
    @@ -48,3 +48,34 @@ test('deepCopy merges without mutating src argument', () => {
       // should not mutate source object
       expect(msg1).toStrictEqual(copy1)
     })
    +
    +describe('CVE-2024-52810', () => {
    +  test('__proto__', () => {
    +    const source = '{ "__proto__": { "pollutedKey": 123 } }'
    +    const dest = {}
    +
    +    deepCopy(JSON.parse(source), dest)
    +    expect(dest).toEqual({})
    +    // @ts-ignore -- initialize polluted property
    +    expect(JSON.parse(JSON.stringify({}.__proto__))).toEqual({})
    +  })
    +
    +  test('nest __proto__', () => {
    +    const source = '{ "foo": { "__proto__": { "pollutedKey": 123 } } }'
    +    const dest = {}
    +
    +    deepCopy(JSON.parse(source), dest)
    +    expect(dest).toEqual({ foo: {} })
    +    // @ts-ignore -- initialize polluted property
    +    expect(JSON.parse(JSON.stringify({}.__proto__))).toEqual({})
    +  })
    +
    +  test('constructor prototype', () => {
    +    const source = '{ "constructor": { "prototype": { "polluted": 1 } } }'
    +    const dest = {}
    +
    +    deepCopy(JSON.parse(source), dest)
    +    // @ts-ignore -- initialize polluted property
    +    expect({}.polluted).toBeUndefined()
    +  })
    +})
    
  • packages/vue-i18n-core/src/components/base.ts+1 1 modified
    @@ -1,7 +1,7 @@
     import { Composer } from '../composer'
     
    -import type { I18nScope } from '../i18n'
     import type { Locale } from '@intlify/core-base'
    +import type { I18nScope } from '../i18n'
     
     export type ComponentI18nScope = Exclude<I18nScope, 'local'>
     
    
  • packages/vue-i18n-core/src/components/DatetimeFormat.ts+5 5 modified
    @@ -1,16 +1,16 @@
    -import { defineComponent } from 'vue'
    -import { assign } from '@intlify/shared'
     import { DATETIME_FORMAT_OPTIONS_KEYS } from '@intlify/core-base'
    +import { assign } from '@intlify/shared'
    +import { defineComponent } from 'vue'
     import { useI18n } from '../i18n'
     import { DatetimePartsSymbol } from '../symbols'
    -import { renderFormatter } from './formatRenderer'
     import { baseFormatProps } from './base'
    +import { renderFormatter } from './formatRenderer'
     
    -import type { VNodeProps } from 'vue'
     import type { DateTimeOptions } from '@intlify/core-base'
    +import type { VNodeProps } from 'vue'
     import type { Composer, ComposerInternal } from '../composer'
    -import type { FormattableProps } from './formatRenderer'
     import type { BaseFormatProps } from './base'
    +import type { FormattableProps } from './formatRenderer'
     
     /**
      * DatetimeFormat Component Props
    
  • packages/vue-i18n-core/src/components/formatRenderer.ts+8 8 modified
    @@ -1,15 +1,15 @@
    +import { assign, create, isArray, isObject, isString } from '@intlify/shared'
     import { h } from 'vue'
     import { getFragmentableTag } from './utils'
    -import { isString, isObject, isArray, assign } from '@intlify/shared'
     
    +import type { DateTimeOptions, NumberOptions } from '@intlify/core-base'
     import type {
       RenderFunction,
       SetupContext,
       VNode,
    -  VNodeChild,
    -  VNodeArrayChildren
    +  VNodeArrayChildren,
    +  VNodeChild
     } from 'vue'
    -import type { NumberOptions, DateTimeOptions } from '@intlify/core-base'
     import type { BaseFormatProps } from './base'
     
     /**
    @@ -61,7 +61,7 @@ export function renderFormatter<
     
       return (): VNodeChild => {
         const options = { part: true } as Arg
    -    let overrides = {} as FormatOverrideOptions
    +    let overrides = create() as FormatOverrideOptions
     
         if (props.locale) {
           options.locale = props.locale
    @@ -78,9 +78,9 @@ export function renderFormatter<
           // Filter out number format options only
           overrides = Object.keys(props.format).reduce((options, prop) => {
             return slotKeys.includes(prop)
    -          ? assign({}, options, { [prop]: (props.format as any)[prop] }) // eslint-disable-line @typescript-eslint/no-explicit-any
    +          ? assign(create(), options, { [prop]: (props.format as any)[prop] }) // eslint-disable-line @typescript-eslint/no-explicit-any
               : options
    -      }, {})
    +      }, create())
         }
     
         const parts = partFormatter(...[props.value, options, overrides])
    @@ -100,7 +100,7 @@ export function renderFormatter<
           children = [parts]
         }
     
    -    const assignedAttrs = assign({}, attrs)
    +    const assignedAttrs = assign(create(), attrs)
         const tag =
           isString(props.tag) || isObject(props.tag)
             ? props.tag
    
  • packages/vue-i18n-core/src/components/index.ts+4 4 modified
    @@ -1,5 +1,5 @@
    -export { ComponentI18nScope, BaseFormatProps } from './base'
    +export { BaseFormatProps, ComponentI18nScope } from './base'
    +export { DatetimeFormat, DatetimeFormatProps, I18nD } from './DatetimeFormat'
     export { FormattableProps } from './formatRenderer'
    -export { Translation, I18nT, TranslationProps } from './Translation'
    -export { NumberFormat, I18nN, NumberFormatProps } from './NumberFormat'
    -export { DatetimeFormat, I18nD, DatetimeFormatProps } from './DatetimeFormat'
    +export { I18nN, NumberFormat, NumberFormatProps } from './NumberFormat'
    +export { I18nT, Translation, TranslationProps } from './Translation'
    
  • packages/vue-i18n-core/src/components/NumberFormat.ts+5 5 modified
    @@ -1,16 +1,16 @@
    -import { defineComponent } from 'vue'
    -import { assign } from '@intlify/shared'
     import { NUMBER_FORMAT_OPTIONS_KEYS } from '@intlify/core-base'
    +import { assign } from '@intlify/shared'
    +import { defineComponent } from 'vue'
     import { useI18n } from '../i18n'
     import { NumberPartsSymbol } from '../symbols'
    -import { renderFormatter } from './formatRenderer'
     import { baseFormatProps } from './base'
    +import { renderFormatter } from './formatRenderer'
     
    -import type { VNodeProps } from 'vue'
     import type { NumberOptions } from '@intlify/core-base'
    +import type { VNodeProps } from 'vue'
     import type { Composer, ComposerInternal } from '../composer'
    -import type { FormattableProps } from './formatRenderer'
     import type { BaseFormatProps } from './base'
    +import type { FormattableProps } from './formatRenderer'
     
     /**
      * NumberFormat Component Props
    
  • packages/vue-i18n-core/src/components/Translation.ts+7 7 modified
    @@ -1,12 +1,12 @@
    -import { h, defineComponent } from 'vue'
    -import { isNumber, isString, isObject, assign } from '@intlify/shared'
    -import { TranslateVNodeSymbol } from '../symbols'
    +import { assign, create, isNumber, isObject, isString } from '@intlify/shared'
    +import { defineComponent, h } from 'vue'
     import { useI18n } from '../i18n'
    +import { TranslateVNodeSymbol } from '../symbols'
     import { baseFormatProps } from './base'
    -import { getInterpolateArg, getFragmentableTag } from './utils'
    +import { getFragmentableTag, getInterpolateArg } from './utils'
     
    -import type { VNodeChild, VNodeProps } from 'vue'
     import type { TranslateOptions } from '@intlify/core-base'
    +import type { VNodeChild, VNodeProps } from 'vue'
     import type { Composer, ComposerInternal } from '../composer'
     import type { BaseFormatProps } from './base'
     
    @@ -59,7 +59,7 @@ export const TranslationImpl = /*#__PURE__*/ defineComponent({
     
         return (): VNodeChild => {
           const keys = Object.keys(slots).filter(key => key !== '_')
    -      const options = {} as TranslateOptions
    +      const options = create() as TranslateOptions
           if (props.locale) {
             options.locale = props.locale
           }
    @@ -73,7 +73,7 @@ export const TranslationImpl = /*#__PURE__*/ defineComponent({
             arg,
             options
           )
    -      const assignedAttrs = assign({}, attrs)
    +      const assignedAttrs = assign(create(), attrs)
           const tag =
             isString(props.tag) || isObject(props.tag)
               ? props.tag
    
  • packages/vue-i18n-core/src/components/utils.ts+2 1 modified
    @@ -1,3 +1,4 @@
    +import { create } from '@intlify/shared'
     import { Fragment } from 'vue'
     
     import type { NamedValue } from '@intlify/core-base'
    @@ -27,7 +28,7 @@ export function getInterpolateArg(
             arg[key] = slot()
           }
           return arg
    -    }, {} as NamedValue)
    +    }, create() as NamedValue)
       }
     }
     
    
  • packages/vue-i18n-core/src/index.ts+83 83 modified
    @@ -1,120 +1,120 @@
    -import { getGlobalThis } from '@intlify/shared'
     import { setDevToolsHook } from '@intlify/core-base'
    +import { getGlobalThis } from '@intlify/shared'
     import { initDev, initFeatureFlags } from './misc'
     
     export {
    -  SchemaParams,
    -  LocaleParams,
    -  Path,
    -  PathValue,
    -  NamedValue,
    -  Locale,
    +  CompileError,
    +  DateTimeOptions,
       FallbackLocale,
    -  LocaleMessageValue,
    -  LocaleMessageDictionary,
    -  LocaleMessageType,
    -  LocaleMessages,
    -  LocaleMessage,
    -  NumberFormat as IntlNumberFormat,
       DateTimeFormat as IntlDateTimeFormat,
       DateTimeFormats as IntlDateTimeFormats,
    -  NumberFormats as IntlNumberFormats,
    -  LocaleMatcher as IntlLocaleMatcher,
       FormatMatcher as IntlFormatMatcher,
    -  MessageFunction,
    -  MessageFunctions,
    -  PluralizationRule,
    +  LocaleMatcher as IntlLocaleMatcher,
    +  NumberFormat as IntlNumberFormat,
    +  NumberFormats as IntlNumberFormats,
       LinkedModifiers,
    -  TranslateOptions,
    -  DateTimeOptions,
    -  NumberOptions,
    -  PostTranslationHandler,
    -  MessageResolver,
    +  Locale,
    +  LocaleMessage,
    +  LocaleMessageDictionary,
    +  LocaleMessages,
    +  LocaleMessageType,
    +  LocaleMessageValue,
    +  LocaleParams,
       MessageCompiler,
       MessageCompilerContext,
    -  CompileError,
       MessageContext,
    -  RemovedIndexResources
    +  MessageFunction,
    +  MessageFunctions,
    +  MessageResolver,
    +  NamedValue,
    +  NumberOptions,
    +  Path,
    +  PathValue,
    +  PluralizationRule,
    +  PostTranslationHandler,
    +  RemovedIndexResources,
    +  SchemaParams,
    +  TranslateOptions
     } from '@intlify/core-base'
     export {
    -  VueMessageType,
    -  DefineLocaleMessage,
    -  DefaultLocaleMessageSchema,
    -  DefineDateTimeFormat,
    -  DefaultDateTimeFormatSchema,
    -  DefineNumberFormat,
    -  DefaultNumberFormatSchema,
    -  MissingHandler,
    -  ComposerOptions,
    +  BaseFormatProps,
    +  ComponentI18nScope,
    +  DatetimeFormat,
    +  DatetimeFormatProps,
    +  FormattableProps,
    +  I18nD,
    +  I18nN,
    +  I18nT,
    +  NumberFormat,
    +  NumberFormatProps,
    +  Translation,
    +  TranslationProps
    +} from './components'
    +export {
       Composer,
       ComposerCustom,
    -  CustomBlock,
    -  CustomBlocks,
    -  ComposerTranslation,
       ComposerDateTimeFormatting,
       ComposerNumberFormatting,
    -  ComposerResolveLocaleMessageTranslation
    +  ComposerOptions,
    +  ComposerResolveLocaleMessageTranslation,
    +  ComposerTranslation,
    +  CustomBlock,
    +  CustomBlocks,
    +  DefaultDateTimeFormatSchema,
    +  DefaultLocaleMessageSchema,
    +  DefaultNumberFormatSchema,
    +  DefineDateTimeFormat,
    +  DefineLocaleMessage,
    +  DefineNumberFormat,
    +  MissingHandler,
    +  VueMessageType
     } from './composer'
     export {
    -  TranslateResult,
    +  TranslationDirective,
    +  vTDirective,
    +  VTDirectiveValue
    +} from './directive'
    +export {
    +  ComposerAdditionalOptions,
    +  ComposerExtender,
    +  createI18n,
    +  ExportedGlobalComposer,
    +  I18n,
    +  I18nAdditionalOptions,
    +  I18nInjectionKey,
    +  I18nMode,
    +  I18nOptions,
    +  I18nScope,
    +  useI18n,
    +  UseI18nOptions
    +} from './i18n'
    +export {
       Choice,
    -  LocaleMessageObject,
    -  PluralizationRulesMap,
    -  WarnHtmlInMessageLevel,
       DateTimeFormatResult,
    +  LocaleMessageObject,
       NumberFormatResult,
    -  VueI18nOptions,
    +  PluralizationRulesMap,
    +  TranslateResult,
       VueI18n,
    -  VueI18nTranslation,
    -  VueI18nTranslationChoice,
       VueI18nDateTimeFormatting,
    +  VueI18nExtender,
       VueI18nNumberFormatting,
    +  VueI18nOptions,
       VueI18nResolveLocaleMessageTranslation,
    -  VueI18nExtender
    +  VueI18nTranslation,
    +  VueI18nTranslationChoice,
    +  WarnHtmlInMessageLevel
     } from './legacy'
    -export {
    -  createI18n,
    -  useI18n,
    -  I18nInjectionKey,
    -  I18nOptions,
    -  I18nAdditionalOptions,
    -  I18n,
    -  I18nMode,
    -  I18nScope,
    -  ComposerAdditionalOptions,
    -  UseI18nOptions,
    -  ExportedGlobalComposer,
    -  ComposerExtender
    -} from './i18n'
    -export {
    -  Translation,
    -  I18nT,
    -  NumberFormat,
    -  I18nN,
    -  DatetimeFormat,
    -  I18nD,
    -  TranslationProps,
    -  NumberFormatProps,
    -  DatetimeFormatProps,
    -  FormattableProps,
    -  BaseFormatProps,
    -  ComponentI18nScope
    -} from './components'
    -export {
    -  vTDirective,
    -  VTDirectiveValue,
    -  TranslationDirective
    -} from './directive'
    -export { I18nPluginOptions } from './plugin'
     export { VERSION } from './misc'
    +export { I18nPluginOptions } from './plugin'
     export { Disposer } from './types'
     
     export type {
    -  IsNever,
       IsEmptyObject,
    -  PickupPaths,
    +  IsNever,
    +  PickupFormatPathKeys,
       PickupKeys,
    -  PickupFormatPathKeys
    +  PickupPaths
     } from '@intlify/core-base'
     
     if (__ESM_BUNDLER__ && !__TEST__) {
    
  • packages/vue-i18n-core/src/utils.ts+9 5 modified
    @@ -1,5 +1,6 @@
     /* eslint-disable @typescript-eslint/no-explicit-any */
     import {
    +  create,
       deepCopy,
       hasOwn,
       isArray,
    @@ -69,7 +70,7 @@ export function handleFlatJson(obj: unknown): unknown {
           let hasStringValue = false
           for (let i = 0; i < lastIndex; i++) {
             if (!(subKeys[i] in currentObj)) {
    -          currentObj[subKeys[i]] = {}
    +          currentObj[subKeys[i]] = create()
             }
             if (!isObject(currentObj[subKeys[i]])) {
               __DEV__ &&
    @@ -108,16 +109,16 @@ export function getLocaleMessages<Messages = {}>(
       const ret = (isPlainObject(messages)
         ? messages
         : isArray(__i18n)
    -      ? {}
    -      : { [locale]: {} }) as Record<string, any>
    +      ? create()
    +      : { [locale]: create() }) as Record<string, any>
     
       // merge locale messages of i18n custom block
       if (isArray(__i18n)) {
         __i18n.forEach(custom => {
           if ('locale' in custom && 'resource' in custom) {
             const { locale, resource } = custom
             if (locale) {
    -          ret[locale] = ret[locale] || {}
    +          ret[locale] = ret[locale] || create()
               deepCopy(resource, ret[locale])
             } else {
               deepCopy(resource, ret)
    @@ -149,7 +150,10 @@ export function adjustI18nResources(
       options: ComposerOptions,
       componentOptions: any
     ): void {
    -  let messages = isObject(options.messages) ? options.messages : {}
    +  // prettier-ignore
    +  let messages = isObject(options.messages)
    +    ? options.messages
    +    : create() as NonNullable<ComposerOptions['messages']>
       if ('__i18nGlobal' in componentOptions) {
         messages = getLocaleMessages(gl.locale.value as Locale, {
           messages,
    
  • packages/vue-i18n-core/src/warnings.ts+1 1 modified
    @@ -1,5 +1,5 @@
    -import { format } from '@intlify/shared'
     import { CORE_WARN_CODES_EXTEND_POINT } from '@intlify/core-base'
    +import { format } from '@intlify/shared'
     
     export const I18nWarnCodes = {
       FALLBACK_TO_ROOT: CORE_WARN_CODES_EXTEND_POINT, // 8
    

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.