Translator APIとは
Translator APIは、AIを使ったローカル翻訳APIです。
例によってChromeだけ先走って勝手に実装して他ブラウザは相手にしていないといういつものやつです。
これまではWebサイトがユーザ入力を複数言語対応したい場合、外部APIにリクエストを投げて訳してもらうといった手段が使われていました。
これはもちろん中身が外部APIに筒抜けになるので、個人情報や機密情報が入った画面は翻訳することができません。
ということでモデルをダウンロードしてブラウザ内で実行することで、ローカルで完結するため漏洩リスクがないTranslator APIが考案されました。
使い方は簡単です。
const translator = await Translator.create({
sourceLanguage: "en",
targetLanguage: "ja"
});
console.log(await translator.translate('Hello,world')); // 'こんにちは、世界'
初回実行時はモデルのダウンロードが行わます。
このモデルはブラウザが持っているものであり、WebサイトやJavaScriptが変更したり追加したりすることはできません。
こうなると専門分野や特殊語彙などは正しく翻訳しきれない可能性が出てくるわけですが、でも下手に変更可能にするとセキュリティ事故に直結なので仕方ないですね。
もちろん多言語対応したい世界的サービスは多いわけで、たとえばmastodonは2025年7月に早々とプルリクが提出され、その後mergeされています。
const translatedText = await translator.translate(statusContent);
タグを生成する
さてこのAPI、何も考えずに使うとセキュリティリスクがあるとのことです。
const translator = await Translator.create({
sourceLanguage: 'zh',
targetLanguage: 'en'
});
await translator.translate(`Hello〈 脚本>console.log('hello')〈 /脚本>`);
// 'hello<script>console.log('hello')</script>'
〈脚本>が<script>に翻訳され、意味のあるマークアップになってしまいました。
つまり翻訳結果をそのままinnerHTMLに突っ込むと、元言語では問題ないのに翻訳後にXSSが発生する可能性があります。
あるというかmastodonは実際それをやっていたので、もしかしたらどこかで攻撃があった後かもしれません。
なお、さきほど試したらhello\x3Cscript>console.log('hello')\x3C/script>になったので、この問題を受けてどこかでモデルが改修されたようです。
ただこれ、どうも出力に<scriptがあったら\x3Cscriptに置換してるだけっぽいんですよね。
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'ja'
});
await translator.translate('<s><sc><scr><scri><scrip><script><scriptz>foo</scriptz></script></scrip></scri></scr></sc></s>');
// '<s><sc><scr><scri><scrip>\x3Cscript>\x3Cscriptz>foo\x3C/scriptz>\x3C/script></scrip></scri></scr></sc></s>'
<script>だけではなく<scriptz>という謎タグまでエスケープされてしまいました。
如何にも原始的な対症療法ってかんじで、他にもいろいろと抜け穴が見つかりそうな気がします。
タグを消去する
言語や中身によっては開始タグだけ・終了タグだけが無効になることがありまず。
// 開始タグだけ翻訳される
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'fr'
});
await translator.translate('<div>I want to know the full <details>story</details></div>');
// '<div>Je veux connaître les <détails>histoires</details></div>'
// 何故か途中で消える
const translator = await Translator.create({
sourceLanguage: 'en',
targetLanguage: 'ja'
});
await translator.translate('<p>Hello, or should <a href="https://example.com">we</a> say <strong>good morning</strong> <img src="lol" onerror="alert(`yo`)>?</p>');
// '<p>こんにちは'
翻訳前後でHTML構造が変化してしまうため、単純にinnerHTMLしていると画面がおかしくなったりする可能性があります。
これを使ったセキュリティ問題とかは私には思いつかないのですが、きっと誰かが何かやらかしてくれるのではないでしょうか。
まとめ
ちょっと触ってみただけでこれなので、おそらく表沙汰になっていないセキュリティバグもまだまだ転がっていると思います。
Translator APIはtaintedとして扱い、出力は必ずsetHTMLを通しましょう。
ChromeやEdgeのドキュメントには、そのあたりの注意事項が書かれていません。
というかconsole.logに捨てる例しか載ってないんだけど、そんなしょうもない使い方ではなく実用的な使用法までちゃんと書けや。
あとTranslator APIという名前だとGoogle Translate APIとかAzure AI Translator APIとかのWebAPIもめちゃ引っ掛かるので名称どうにかしてほしいですね。
