Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Memory-exhaustion DoS in BMP decoder (bundled bmp-ts dependency) via unbounded width/height

オープン
#1,415 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
62/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
node.js, typescript
領域
security

調査の方向性

plugins/js-bmp/src/index.ts と、レポートで説明されているバンドル済みの bmp-ts decoder.js の allocation および fill のパスから始めます。提供された作成済みの BMP 再現ケースを Jimp.read() に対して実行してメモリ増加の挙動を確認し、その後、allocation 前に過大な dimensions を拒否するテストカバレッジを追加します。完了の条件は、大きな allocation を行わずに再現ケースが拒否され、通常の BMP デコードが引き続き機能することです。

索引モデルが issue の本文から書いたものです。

説明

Summary

@jimp/js-bmp delegates BMP decoding entirely to the bmp-ts npm package with no validation of its own. bmp-ts's decoder allocates its output pixel buffer directly from the BMP header's width/height fields with no upper bound and no comparison against the actual input size:

// [email protected] dist/commonjs/decoder.js:153
this.data = Buffer.alloc(this.width * this.height * 4);

For RLE4/RLE8-compressed BMPs, the very next thing that happens is:

// decoder.js:201 (bit4) and :279 (bit8)
this.data.fill(0);

Buffer.fill() forces real physical memory to be committed across the whole buffer (unlike Buffer.alloc's lazily-zero-mapped pages), and this happens before any actual pixel bytes are read from the file, so a tiny file with a big declared width/height is enough to force a large real memory allocation.

Proof of Concept

A crafted 1078-byte BMP (valid BM magic + 40-byte BITMAPINFOHEADER, bitPP=8, compression=1 i.e. BI_RLE8, width=10000, height=10000, a 256-entry zero palette, and no actual RLE pixel data after the palette) causes roughly 405MB of RSS growth in a single Jimp.read() call, confirmed against the real published [email protected] (which bundles [email protected]):

input size 1078 bytes   rss before ~67.7MB
Jimp.read(buffer) -> eventually throws RangeError (only AFTER the .fill(0) commits memory)
time 278ms              rss after ~472.4MB   (~405MB forced commit from a 1KB file)

Scaling width/height further is unbounded — nothing in bmp-ts or in @jimp/js-bmp's wrapper (plugins/js-bmp/src/index.ts, which calls BMP.decode() directly with no width/height sanity check before delegating) caps the allocation. A handful of concurrent uploads of ~1KB crafted files could force multi-GB memory growth or an allocator OOM in any service that calls Jimp.read() on user-uploaded images (a very common pattern — avatar/image upload handling).

This is a memory-exhaustion availability issue (CWE-400/789), not memory corruption — Node's Buffer/TypedArray bounds checks prevent any actual out-of-bounds read/write.

Suggested Fix

Before allocating the output buffer, validate that width * height * bytesPerPixel is consistent with the actual input buffer size (or with a reasonable configurable maximum), and reject the file early if not. This applies both in bmp-ts's decoder.js (root cause) and as a defense-in-depth check in @jimp/js-bmp's wrapper before it delegates to bmp-ts, since jimp is the package most people actually depend on directly.

Disclosure note

Checked for existing reports first: no GHSA/CVE/OSV advisory exists for bmp-ts, jimp, or @jimp/js-bmp. Neither repo has SECURITY.md or GitHub private vulnerability reporting enabled, so filing this as a plain public issue rather than a private advisory — severity is DoS-only (not RCE/memory-corruption), so this seemed reasonable to disclose directly; happy to move to a private channel if one gets set up.

主要言語
TypeScript
スター
14.7k
フォーク
777
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

jimp-dev/jimp のほかの issue

jimp-dev/jimp の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。