So What!?

カテゴリ

記事

連絡先

何か間違っている情報などがあればTwitterにてメッセージください。

ご注意

このBlogはアクセスデータをGoogle Analyticsおよび、Cloudflare Analyticsに送信しています。また研究開発用にSentryにパフォーマンスデータを送信しています。それ以外のデータは収集していません。

DependabotAlert-y18n

2021年5月11日

3/31に報告された「y18n」のDependabot Alertのメモ。

この脆弱性はv3.2.1以前、v4.0.0以前、v5.0.4以前にて発生している。修正バージョンはすぐに公開されており、それぞれv3.2.2、v4.0.1、v5.0.5にアップグレードすることが推奨されている。

カテゴリは「high severity」。記事執筆時点での最新バージョンはv5.0.8。

GitHub Advisory Database番号は「CVE-2020-7774」。

y18nとは

y18nはyargsで使われている国際化ライブラリ。i18nのyargs版だからy18nなんだと思う。多分。

y18nの簡単な使い方。例えば、以下のような2つのjsonファイルを用意したとする。

en.json

{
  "hello": "hello",
  "world": "world"
}

ja.json

{
  "hello": "こんにちは",
  "world": "世界"
}

で、これを以下のように使う。

const y18n = require('y18n');
const __ = y18n({
  locale: 'en',
  directory: './locales'
}).__;

console.log(`${__`hello`} ${__`world`}`); // localeが`en`なら「hello world」で`ja`なら「こんにちは 世界」と出力される

逆に、JSONファイルに文字を出力することもできるので、プログラムを通して言語ごとの辞書を作ることもできる。

脆弱性について

y18nに存在していた脆弱性はPrototype Pollutionと呼ばれるJavaScriptの__proto__プロパティに関連したもの。

日本語では、プロトタイプ汚染と呼ばれていて「Node.jsにおけるプロトタイプ汚染攻撃とは何か」という記事が分かりやすい。

y18nではsetLocaleの引数に__proto__を渡すと任意のキーバリューオブジェクトを__proto__にセットできるようになっていたようだ。

元々のクラスのソースコードを一部抜粋。

class Y18N {
    // ...
    setLocale(locale) {
        this.locale = locale;
    }
    updateLocale(obj) {
        // ...
        for (const key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                this.cache[this.locale][key] = obj[key];
            }
        }
    }
    // ...
}

this.cacheの初期値が単純なオブジェクト({})だったため、setLocaleの引数に__proto__を渡したあと、updateLocaleにキーバリューオブジェクトを渡すと、

this.cache['__proto__'][key] = obj[key];

が実行されることになり、結局はグローバルオブジェクトを含む全てのオブジェクトの下に{key: value}がセットされる。

修正後はthis.cacheの初期値をObject.create(null)にしたことで、プロトタイプチェーンから切り離したオブジェクトを作成されるようになっていた。

とても勉強になりました。