Hello! I'm Hong Minhee (洪 民憙), an open source software engineer in my late 30s, living in Seoul, Korea. I'm bisexual and non-binary (they/them), and an enthusiastic advocate of free/open source software and the fediverse.
I work full-time on @fedify, an ActivityPub server framework in TypeScript, funded by @sovtechfund. I'm also the creator of @hollo, a single-user ActivityPub microblog; @botkit, an ActivityPub bot framework; Hackers' Pub, a fediverse platform for software developers; and LogTape, a logging library for JavaScript and TypeScript.
I have a long interest in East Asian languages (CJK) and Unicode. I post mostly in English here, though occasionally in Japanese or in mixed-script Korean (國漢文混用體), a traditional writing style that interleaves Chinese characters with the native Korean alphabet. Wanting to write in that style was actually one of the reasons I joined the fediverse. Feel free to talk to me in English, Korean, Japanese, or even Literary Chinese!
安寧하세요! 저는 서울에 살고 있는 30代 後半의 오픈 소스 소프트웨어 엔지니어 洪民憙입니다. 兩性愛者(bisexual)이자 논바이너리(non-binary)이며, 自由·오픈 소스 소프트웨어(F/OSS)와 聯合宇宙(fediverse)의 熱烈한 支持者이기도 합니다.
STF(@sovtechfund)의 支援을 받아 TypeScript用 ActivityPub 서버 프레임워크 @fedify 開發에 專業으로 任하고 있습니다. 그 外에도 싱글 유저用 ActivityPub 마이크로블로그 @hollo, ActivityPub 봇 프레임워크 @botkit, 소프트웨어 開發者를 위한 聯合宇宙 플랫폼 Hackers' Pub, JavaScript·TypeScript用 로깅 라이브러리 LogTape 等의 製作者이기도 합니다.
東아시아 言語(이른바 CJK)와 Unicode에도 關心이 많습니다. 이 計定에서는 主로 英語로 포스팅하지만, 때때로 日本語나 國漢文混用體 韓國語로도 씁니다. 聯合宇宙에 오게 된 動機 中 하나가 바로 國漢文混用體로 글을 쓰고 싶었기 때문이기도 하고요. 韓國語, 英語, 日本語, 아니면 漢文으로도 말을 걸어주세요!
If you use BotKit, update to a patched release now. CVE-2026-50131 affects Fedify's SSRF protection for remote document and media loading, and BotKit inherits the exposure through its dependency on Fedify.
Fedify validates remote ActivityPub document and media URLs before fetching them, including direct IP literals and hostnames resolved through DNS, to protect against Server-Side Request Forgery (SSRF). The vulnerable path is validatePublicUrl(): affected versions rejected common private and local addresses, but still treated several special-use IPv4 ranges—including carrier-grade NAT, benchmarking, multicast, reserved, and documentation networks—as public internet destinations. An attacker could use these special-use IP address ranges to bypass Fedify's SSRF protections and cause a BotKit server to initiate requests to non-public or special-use network destinations, depending on the deployment environment and network routing.
The fix makes Fedify validate resolved addresses against public-network expectations instead of relying on the incomplete denylist. It rejects additional special-use IPv4 ranges before remote document or media fetching proceeds.
All versions of BotKit up to 0.3.3 (in the 0.3.x branch) and 0.4.2 (in the 0.4.x branch) are affected. Patched releases are 0.3.4 and 0.4.3.
If you run Hollo, update to a patched release now. CVE-2026-50131 affects Fedify's SSRF protection, and Hollo depends on Fedify for ActivityPub federation.
Fedify guards against SSRF (Server-Side Request Forgery) when fetching remote ActivityPub objects, documents, and media by validating that the resolved destination is a public IP address. The previous SSRF fix (GHSA-p9cg-vqcc-grcx) blocked common private and local ranges such as 10.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, and 192.168.0.0/16, but the validation was incomplete—it still treated several special-use IPv4 ranges as public destinations that should have been rejected. These include carrier-grade NAT (100.64.0.0/10), benchmarking and internal testing networks (198.18.0.0/15), multicast (224.0.0.0/4), reserved (240.0.0.0/4), IETF protocol assignments (192.0.0.0/24), and documentation ranges (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24).
An attacker who controls a remote ActivityPub object or media URL could therefore cause a Hollo instance to initiate outbound requests to non-public or special-use network ranges, depending on the deployment environment and network routing.
All Hollo versions up to and including 0.7.17, 0.8.6, and 0.9.3 are affected. Patched releases are 0.7.18 for the 0.7.x series, 0.8.7 for the 0.8.x series, and 0.9.4 for the 0.9.x series.
Fedify security updates: 1.9.12, 1.10.11, 2.0.20, 2.1.16, and 2.2.5
If you use Fedify, update to a patched release now. CVE-2026-50131 affects Fedify's public URL validation for remote document and media loading. An attacker could use special-use IP address ranges to bypass Fedify's SSRF protections and cause a Fedify server to initiate requests to non-public or special-use network destinations, depending on the deployment environment and network routing.
Fedify validates remote ActivityPub document and media URLs before fetching them, including direct IP literals and hostnames resolved through DNS. The vulnerable path is validatePublicUrl(): affected versions rejected common private and local addresses, but still treated several special-use IPv4 ranges as public internet destinations. That gap could allow outbound requests to ranges such as carrier-grade NAT, benchmarking, multicast, reserved, and documentation networks.
The fix makes Fedify validate resolved addresses against public-network expectations instead of relying on the incomplete denylist. It rejects additional special-use IPv4 ranges and IPv6 translation or tunneling prefixes, including NAT64, Teredo, and 6to4 addresses, before remote document or media fetching proceeds.
For years I worked in Python and dreamed in Haskell on weekends. When I needed
a script, Python. When I wanted the type system to hold me accountable,
Haskell. Somewhere between the two sat TypeScript, and I knew it. Practical
where Haskell is austere, typed where Python isn't. But I kept my distance.
tsconfig.json, .eslintrc, .prettierrc, babel.config.js. Files you have
to create before you've written a single line of actual code. Every time I
thought about trying it, I looked at the list and gave up. The JavaScript
ecosystem always felt to me like an amusement park where you have to wait in a
long queue just to get inside.
Deno dissolved that queue. No configuration files, no node_modules, no
agonizing over which package manager to use. Just deno run main.ts. The first
time I actually wrote TypeScript properly, I couldn't understand why I'd put it
off so long. What I'd been avoiding wasn't TypeScript. It was the ritual
surrounding TypeScript.
What hooked me
At first I couldn't point to one killer feature. The appeal was that everything
seemed to be pulling in the same direction. The fetch() I used in browsers
worked the same way on the server. Web Crypto API was just there. MDN
effectively became Deno's documentation. Instead of installing packages, you
imported ESM by URL, thinking about dependencies in an entirely different way.
Having deno fmt, deno lint, deno test, deno bench, and deno check all
in a single binary was part of the same logic. No installing ESLint, no wiring
up Prettier, no untangling configuration conflicts between the two. That
convenience had an attitude behind it.
The pattern was obvious enough: build on web standards, then ship the boring
tools yourself.
Chasing Node.js
Today's Deno feels like it's drifting away from that.
npm: specifier support, node_modules back in play, node:* module
compatibility. Then in Deno 2.8, deno add without a specifier now adds an npm
package by default. JSR was introduced as an answer to npm's stagnation, as the
future of JavaScript packaging. These decisions make that announcement look
distant. I can understand each one in isolation. Put them together, though, and
the shape is hard to ignore: Deno is spending more and more of its energy
catching up to Node.js.
The OS/2 story comes to mind. IBM expected that building Windows compatibility
into OS/2 would pull Windows users across. What actually happened was the
opposite: developers realized they could target Windows and have it run on both
platforms, so there was no reason to learn the OS/2 API separately. Deno
pushing further toward Node.js compatibility has the same dynamic. The more
compatible Deno becomes, the less reason library authors have to think about it
specifically.
Early Deno set the agenda. Web standards, the permission model, URL imports,
JSR: Deno put these down and the ecosystem responded. What Deno is doing now
runs in the opposite direction, catching up to what the ecosystem already has.
On the defensive
There's a more specific frustration here. Deno had a fight it could have led
rather than chased.
What drove me away from the JavaScript ecosystem wasn't Node.js itself. It was
the full combination: Node.js + npm + TypeScript + Vite + ESLint + Prettier +
Vitest. That stack was the problem, and Deno was already doing well against it.
deno fmt, deno lint, deno test, deno bench, deno check, and in
2.4, deno bundle came back. It had been deprecated once and then
restored; that round trip is its own admission that the direction was right.
The most visible gap that remains is the dev server: HMR, live reload, an asset
pipeline, and the plugin ecosystem that accumulates on top of all that.
Fresh 2.0, Deno's own framework, chose not to fill that gap from within Deno and adopted Vite instead.
That disappointed me. Making Vite run well on Deno and making Deno a
self-sufficient development environment are two entirely different directions.
Once your own framework makes that choice, you can't expect the wider ecosystem
to go the other way.
But vertical integration alone might not have been enough. Individual component
quality matters too. If deno lint and deno fmt were clearly better than
ESLint and Prettier, developers would reach for them even in Node.js projects.
That could have been the Trojan horse. Once enough projects are using Deno's
tools without using the Deno runtime, the next question follows naturally.
ESLint and Prettier seemed unmovable, and yet Biome and the Ox series (Oxlint,
Oxfmt) are finding their footing. The market was always there. Better tools
just weren't. Deno could have gotten there first.
The clock I keep thinking about
Why didn't Deno hold the course? This is speculation, but here's my read.
The integrated toolchain path required patience. Getting developers to feel the
pain of configuration complexity, making Deno the place they move to, waiting
for the ecosystem to grow comfortable with Deno's way of doing things. All of
that takes time. Node.js is a community project under the OpenJS Foundation.
There's no investor clock pushing it, and the project doesn't wobble if the
ecosystem moves slowly.
Deno Land Inc. is different. A VC-backed company has a clock. How long that
clock allows for a patient fight is not the same as what a community project
can afford. Expanding Node.js compatibility produces visible results faster
than the slow alternative. From the outside, I can't tell when I'm seeing a
product decision and when I'm seeing a runway decision. What I can say is that
the urgency Deno has been showing doesn't sit well with the direction it
originally chose.
Even so
For all my griping, I still build most of my own libraries Deno-first. I
publish to JSR even when I also publish to npm. I try to depend only on web
standard APIs, and I use Deno's built-in tools for linting and formatting. I'm
still rooting for Deno.
But even I have retreated in places. I now rely on node:test and
node:assert/strict for testing, because it's the easiest way
to run the same tests across Deno, Node.js, and Bun without any special
dependencies. JSR was launched as an answer to npm's stagnation, and I've
started to feel JSR stagnating too. I often catch myself wondering whether to
drop it. I got excited about Deno KV and now I just use node:sqlite, which
runs fine on Deno anyway.
If someone like me is already making these retreats, I wonder what Deno looks
like to someone with no attachment to it at all. That worries me, because I
still want Deno to win some version of this fight. I'm just less sure lately
that Deno wants to win the same fight I signed up for.
Git GUI displaying a commit graph with branching and merge history, branch and tag labels, and a detailed view of the selected commit with file changes in light mode
ALT text
Git GUI displaying a commit graph with branching and merge history, branch and tag labels, and a detailed view of the selected commit with file changes in dark mode
聯合宇宙 처음 始作한 건 아마 2017年頃? 트剩餘에 計定 만들었다가 잘 適應 못 하고, mastodon.social로 갔던 것 같다. 그 뒤로 國漢文으로 글 쓰는데 사람들이 읽기 不便하다고 하니까 國漢文에 自動으로 <ruby>로 한글 讀音 붙게 하는 機能이 必要해서 直接 ActivityPub 소프트웨어 具顯할 생각을 했고… 그 뒤로는…
聯合宇宙 처음 始作한 건 아마 2017年頃? 트剩餘에 計定 만들었다가 잘 適應 못 하고, mastodon.social로 갔던 것 같다. 그 뒤로 國漢文으로 글 쓰는데 사람들이 읽기 不便하다고 하니까 國漢文에 自動으로 <ruby>로 한글 讀音 붙게 하는 機能이 必要해서 直接 ActivityPub 소프트웨어 具顯할 생각을 했고… 그 뒤로는…
There's a Matrix room for #Fedify contributors, open to anyone curious about how development happens. Feel free to drop in or lurk; small questions are fine too.
Are there any F/OSS alternatives to issue trackers like JIRA or Linear? I'd like something that's easy to use and works well for both engineering and non-engineering teams.
Due to recent regulation changes (전기통신사업법), the South Korean government is requiring internet communities and forum owners to scan every user uploaded images and videos on their website, by AI.The hardware to run these AI models are also not provided by government, website owners have to buy datacenter grade Nvidia GPUs by themselves, putting financial pressure to small businesses and forums.
Websites will need to implement these hardware and software features, starting immediately from July 1st, which is just next month.
Here is the original image provided from Korean government, specifying the hardware requirements for AI models. I also added English translated image, made with nano banana (sorry for using ai for this...)
Small fedi badge update: the service has moved to a new domain. Please update your badges to use fedi-badge.minhee.org instead of fedi-badge.deno.dev. The old domain will stop working in July.
I also shipped a couple of related changes. Badges can now show the logo of the software an instance is running, like Mastodon, Misskey, Pleroma, and a few others, detected via NodeInfo. If the software isn't recognized, it falls back to the generic fediverse logo.
The service also moved from Deno Deploy Classic, which is sunsetting, to Cloudflare Workers.
ALT text
Various types of fedi badges. New fedi badges have their software logos too.
Small fedi badge update: the service has moved to a new domain. Please update your badges to use fedi-badge.minhee.org instead of fedi-badge.deno.dev. The old domain will stop working in July.
I also shipped a couple of related changes. Badges can now show the logo of the software an instance is running, like Mastodon, Misskey, Pleroma, and a few others, detected via NodeInfo. If the software isn't recognized, it falls back to the generic fediverse logo.
The service also moved from Deno Deploy Classic, which is sunsetting, to Cloudflare Workers.
ALT text
Various types of fedi badges. New fedi badges have their software logos too.