[Bug] I18n language validation via `in` lets ?lang=constructor break all Panel translations
What happened? / 问题描述
I18n validates the language argument with the in operator, which walks the prototype chain.
Any Object.prototype key (constructor, toString, __proto__, valueOf, ...) therefore passes
validation, and this.translations is assigned a function or Object.prototype instead of a locale
object.
Every subsequent t() lookup then fails, so the Panel renders raw translation keys
(ui.panel.ready instead of Ready) and emits a console.warn per call.
This is reachable from untrusted input: the demo entry reads lang from the URL query string and
casts it with as, so there is no runtime validation.
https://github.com/alibaba/page-agent/blob/main/packages/page-agent/src/demo.ts#L35
const language = (url.searchParams.get('lang') as 'zh-CN' | 'en-US') || 'zh-CN'Expected: unknown values fall back to en-US, which already works for ordinary invalid input
such as ?lang=fr-FR.
Actual: Object.prototype keys bypass the fallback and break every translation.
To be precise about severity: this is not prototype pollution — nothing is written to any prototype. It is a validation gap that silently degrades the UI.
Root cause
https://github.com/alibaba/page-agent/blob/main/packages/ui/src/i18n/index.ts#L14
this.language = language in locales ? language : 'en-US''constructor' in locales is true, while Object.hasOwn(locales, 'constructor') is false.
Suggested fix
this.language = Object.hasOwn(locales, language) ? language : 'en-US'Object.hasOwn is ES2022 and the repo targets es2025 with lib: ["ESNext", "DOM"], so this needs
no downlevel handling.
Related, same root cause
getNestedValue reduces with current?.[key], which also traverses the prototype chain, so
t('toString') returns a Function even though the signature declares string:
https://github.com/alibaba/page-agent/blob/main/packages/ui/src/i18n/index.ts#L33
While investigating I also hit two unrelated edge cases in the same file — a TypeError when a key
resolves to an intermediate object and params are passed, and empty-string translations being
treated as missing by the if (!value) check. Those are separate bugs; I'd rather file them
individually than mix them in here. Let me know if they're worth reporting.
How to reproduce / 如何复现
Verified against packages/ui/src/i18n/index.ts on main (b7401a0), Node 22.23.0.
Casts are needed because SupportedLanguage is a union type — which is exactly the point: the
values below arrive as an unvalidated string at runtime.
import { I18n } from '@page-agent/ui'
new I18n('fr-FR' as any).t('ui.panel.ready') // 'Ready' ← fallback works
new I18n('constructor' as any).t('ui.panel.ready') // 'ui.panel.ready' ← broken
new I18n('__proto__' as any).t('ui.panel.ready') // 'ui.panel.ready' ← broken
new I18n('toString' as any).t('ui.panel.ready') // 'ui.panel.ready' ← brokenObserved output, including getLanguage() and the warning count:
?lang=en-US getLanguage()=en-US t()="Ready" warns=0
?lang=zh-CN getLanguage()=zh-CN t()="准备就绪" warns=0
?lang=fr-FR getLanguage()=en-US t()="Ready" warns=0
?lang=constructor getLanguage()=constructor t()="ui.panel.ready" warns=1
?lang=__proto__ getLanguage()=__proto__ t()="ui.panel.ready" warns=1
?lang=toString getLanguage()=toString t()="ui.panel.ready" warns=1Note that getLanguage() also returns the bogus value rather than the applied fallback.
In a demo build the same thing is triggered purely from the URL, e.g. loading
page-agent.demo.js?lang=constructor.
Version
1.12.2
Browser
Not browser-specific — reproduces in Node against the @page-agent/ui source.
Before submitting
- I will be polite and respectful. / 我会保持礼貌与尊重。
- I have read the Code of Conduct. / 我已阅读行为准则。
- I have searched existing issues and this is not a duplicate.
Per #349 I'm asking before writing any code:
would you like a PR for the one-line Object.hasOwn fix? packages/ui has no test setup yet, so a
regression test would also need a vitest.config.js following the packages/llms template — happy
to keep that out of scope and send the one-liner alone if you prefer.
Source: alibaba/page-agent