Stream chunking anti-pattern in `wtfjs.js` causes Markdown/UTF-8 corruption and duplicate banners
Author: codeCraft-RitikCreated Sep 14, 2026Updated Sep 14, 2026
Issue : Stream chunking anti-pattern in wtfjs.js causes Markdown/UTF-8 corruption and duplicate banners
Severity & Impact
- Severity: Medium–High
- Impact:
- Multi-byte UTF-8 sequences (Hindi, Chinese, Sinhalese characters, and emojis) and Markdown formatting blocks (code fences, tables) are arbitrarily truncated and corrupted when files exceed the default 64KB stream buffer size.
- The update notification banner is pushed to the stream once per chunk, resulting in multiple duplicate update boxes being injected throughout the document.
Affected File
wtfjs.js(Line 74–91)
Root Cause Analysis
In wtfjs.js:
fs.createReadStream(translation)
.pipe(
obj(function (chunk, enc, cb) {
const message = [];
if (notifier.update) {
message.push(
`Update available: {green.bold ${notifier.update.latest}} {dim current: ${notifier.update.current}}`
);
message.push(`Run {blue npm install -g ${pkg.name}} to update.`);
this.push(boxen(message.join("\n"), boxenOpts));
}
this.push(msee.parse(chunk.toString(), mseeOpts));
cb();
})
)
.pipe(pager());fs.createReadStream emits data in 64KB chunks (highWaterMark: 64 * 1024).
README.mdis ~75KB (2 chunks).README-zh-cn.mdis ~76KB (2 chunks).README-hi.mdis ~98KB (2 chunks).README-si.mdis ~208KB (4 chunks).
- UTF-8 and Markdown Splitting: Slicing at an arbitrary 64KB byte offset can bisect a 3- or 4-byte UTF-8 character, producing replacement characters (``) or malformed glyphs. It also splits markdown constructs (e.g.
```jsfences, tables), causingmsee.parse()to render broken ANSI escapes in the terminal pager. - Banner Duplication:
if (notifier.update)executes inside the per-chunk transform handler. When an update is available,this.push(boxen(...))runs on every chunk, causing duplicate notification boxes to appear in the middle of reading the guide.
Minimal Reproducible Example
Run a test counting chunks on README-si.md (208KB):
$ node -e "
const fs = require('fs');
let chunks = 0;
fs.createReadStream('README-si.md').on('data', () => chunks++).on('end', () => console.log('Chunks:', chunks));
"
# Chunks: 4 -> Update box pushed 4 times; Markdown sliced 4 times!Proposed Fix
Read the translation file as a complete UTF-8 string with fs.readFile before formatting, ensuring clean Markdown parsing and an isolated single update banner:
--- a/wtfjs.js
+++ b/wtfjs.js
@@ -74,19 +74,18 @@ fs.stat(translation, function (err, stats) {
- fs.createReadStream(translation)
- .pipe(
- obj(function (chunk, enc, cb) {
- const message = [];
-
- if (notifier.update) {
- message.push(
- `Update available: {green.bold ${notifier.update.latest}} {dim current: ${notifier.update.current}}`
- );
- message.push(`Run {blue npm install -g ${pkg.name}} to update.`);
- this.push(boxen(message.join("\n"), boxenOpts));
- }
-
- this.push(msee.parse(chunk.toString(), mseeOpts));
- cb();
- })
- )
- .pipe(pager());
+ fs.readFile(translation, "utf8", function (readErr, content) {
+ if (readErr) {
+ console.error(readErr);
+ return;
+ }
+
+ let output = "";
+ if (notifier.update) {
+ const message = [
+ `Update available: ${chalk.green.bold(notifier.update.latest)} ${chalk.dim("current: " + notifier.update.current)}`,
+ `Run ${chalk.blue("npm install -g " + pkg.name)} to update.`,
+ ];
+ output += boxen(message.join("\n"), boxenOpts) + "\n\n";
+ }
+
+ output += msee.parse(content, mseeOpts);
+
+ const p = pager();
+ p.end(output);
+ });Source: denysdovhan/wtfjs