{"id":"MAL-2026-18182","summary":"Malicious code in test-brotli2-testmetest (npm)","details":"test-brotli2-testmetest 1.0.0 ships a rebuild of the data-pipeline-testmetest 2.0.1 credential stealer and runs it on `npm install`: its `install` script runs `node-gyp rebuild`, and the `binding.gyp` source `\u003c!(env node index.js \u003e/dev/null 2\u003e&1; echo stub.c)` makes node-gyp run `index.js`, an obfuscated loader that decrypts a Brotli-compressed payload and pipes it into Bun. Published by npm account `testnewtestme2` on 2026-10-21.\n\n---\n_-= Per source details. Do not edit below this line.=-_\n\n## Source: amazon-inspector (191cc40d7896b393d37ba01dd32b1087b769c9fc7dd7b2debb32ba4ef34de11d)\nThe package's scripts.install runs node-gyp rebuild, and binding.gyp uses GYP command-expansion (`\u003c!(env node index.js...; echo stub.c)`) in its sources list to invoke index.js during the configure phase. The binding.gyp declares target type 'none' and ships no C/C++ sources, so there is nothing to actually build — the file exists solely to trigger execution of index.js at install. index.js is a ~586 KB Caesar-shifted (+5) character-code array passed to eval; the decoded program imports node:crypto and uses createDecipheriv('aes-128-gcm',...) to decrypt further hex ciphertext blobs and execute the plaintext. No readable logic, URLs, or purpose is exposed in source. Installing this package on a default `npm install` runs this opaque encrypted payload on the installer's machine. CWE-506.\n","modified":"2026-10-22T06:45:05.741775574Z","published":"2026-10-21T18:00:00Z","database_specific":{"iocs":{"files":[{"source":"PACKAGE_ARCHIVE","digests":{"sha256":"9a876c0a21782b54495d13be1db41e55da1a386c01a3f8dcd15643c609056663"},"note":"install hook: node-gyp runs `env node index.js`","paths":["binding.gyp"]},{"source":"PACKAGE_ARCHIVE","digests":{"sha256":"930736600c86e9daeb6d8d87a4d821fa0b721302bcffc6277d95512dff4c0a25"},"note":"obfuscated loader; decrypts a Brotli-compressed payload and pipes it into `bun run -`","paths":["index.js"]},{"digests":{"sha256":"0084e249dc90d3f08528a519da95bf54967c9f9b996c047f6dc2327f74182d72"},"note":"decrypted 435 KB Bun payload, a rebuild of the data-pipeline-testmetest 2.0.1 stealer","source":"IN_MEMORY"}]},"malicious-packages-origins":[{"sha256":"191cc40d7896b393d37ba01dd32b1087b769c9fc7dd7b2debb32ba4ef34de11d","source":"amazon-inspector","versions":["1.0.0"],"id":"IN-MAL-2026-021575","import_time":"2026-10-22T06:30:24.528135696Z","modified_time":"2026-10-22T06:11:24Z"}]},"references":[{"type":"PACKAGE","url":"https://www.npmjs.com/package/test-brotli2-testmetest/v/1.0.0"}],"affected":[{"package":{"name":"test-brotli2-testmetest","ecosystem":"npm","purl":"pkg:npm/test-brotli2-testmetest"},"versions":["1.0.0"],"database_specific":{"indicators":{"package_integrity":[{"hashes":{"sha512_sri":"sha512-FQe/UXjeU4p6tOlY+nEze9LMuxdDaGHlCUejXIDyg0WCwwFgKLE0HbXXGWmjX0mW3H33j68QCm7h7+DoJt27Vw==","sha1":"4adb5bcd230d3da102e7cafc49916d6e0592b3a1"},"filename":"test-brotli2-testmetest-1.0.0.tgz"}],"evidence_files":[{"tlsh":"d3c08c3cb4380a453ad8082490e8840264b202a3081a2440e6da60286fb841f2449b9e","path":"binding.gyp","sha256":"9a876c0a21782b54495d13be1db41e55da1a386c01a3f8dcd15643c609056663"},{"path":"index.js","sha256":"930736600c86e9daeb6d8d87a4d821fa0b721302bcffc6277d95512dff4c0a25","tlsh":"20c4f7d3578c1beda6944cea520c3617a4f2c17b3c6e228dfae24617b43ee117925b70"}]},"cwes":[{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"name":"Embedded Malicious Code","cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature."}],"source":"https://github.com/ossf/malicious-packages/blob/main/osv/malicious/npm/test-brotli2-testmetest/MAL-2026-18182.json"}}],"schema_version":"1.9.0","credits":[{"name":"Amazon Inspector","contact":["inspector-research@amazon.com"],"type":"FINDER"},{"name":"Robin Frehner, Protet","contact":["https://protet.io","mailto:hello@protet.io"],"type":"FINDER"}]}