Malicious traffic trying to exploit path traversal in `@netlify/ipx` dependency `sharp`

My site prismatic-genie-9fcc79 usually gets a few hits a week, but on 28 Feb it started getting 13k failed Serverless function calls per day. They all look like this:

AM: e3e99752 Duration: 88.14 ms	Memory Usage: 135 MB	
Mar 5, 10:27:53 AM: f2892af4 ERROR  Error: Expected integer between 1 and 100 for quality but received N'-bo2sw6t-, of type string
Mar 5, 10:27:53 AM: f2892af4 ERROR      at Object.invalidParameterError (/var/task/node_modules/sharp/lib/is.js:135:10)
Mar 5, 10:27:53 AM: f2892af4 ERROR      at Sharp.jpeg (/var/task/node_modules/sharp/lib/output.js:321:18)
Mar 5, 10:27:53 AM: f2892af4 ERROR      at Sharp.toFormat (/var/task/node_modules/sharp/lib/output.js:277:28)
Mar 5, 10:27:53 AM: f2892af4 ERROR      at /var/task/node_modules/ipx/dist/index.cjs:526:23
Mar 5, 10:27:53 AM: f2892af4 ERROR      at async _handleRequest (/var/task/node_modules/ipx/dist/index.cjs:598:28)
Mar 5, 10:27:53 AM: f2892af4 ERROR      at async handler (/var/task/node_modules/@netlify/ipx/dist/index.js:144:25)
Mar 5, 10:27:53 AM: f2892af4 Duration: 61.18 ms	Memory Usage: 135 MB	
Mar 5, 10:27:53 AM: f01a14bc ERROR  Error: Expected positive integer for width but received ../../etc/passwd of type string
Mar 5, 10:27:53 AM: f01a14bc ERROR      at Object.invalidParameterError (/var/task/node_modules/sharp/lib/is.js:135:10)
Mar 5, 10:27:53 AM: f01a14bc ERROR      at Sharp.resize (/var/task/node_modules/sharp/lib/resize.js:259:16)
Mar 5, 10:27:53 AM: f01a14bc ERROR      at Object.apply (/var/task/node_modules/ipx/dist/index.cjs:266:17)
Mar 5, 10:27:53 AM: f01a14bc ERROR      at applyHandler (/var/task/node_modules/ipx/dist/index.cjs:201:18)
Mar 5, 10:27:53 AM: f01a14bc ERROR      at /var/task/node_modules/ipx/dist/index.cjs:523:17
Mar 5, 10:27:53 AM: f01a14bc ERROR      at async _handleRequest (/var/task/node_modules/ipx/dist/index.cjs:598:28)
Mar 5, 10:27:53 AM: f01a14bc ERROR      at async handler (/var/task/node_modules/@netlify/ipx/dist/index.js:144:25)

Is there a path traversal issue with sharp’s jpg? And is there anything you guys can do about this flood of obviously-malicious traffic? Note that my site uses NextJS, but my package-lock.json does not include sharp, so it seems like this is a dependency on your side.

This site is using NextJS 12.2.5, which is quite old and had other DoS issues with next/image, so I’ll update it. But I’m not sure if that will stop the traffic…

We’ve dropped support for Next.js 12 and Runtime v4 for more than a year now. Runtime v5 doesn’t use ipx, so this is no longer an issue.

Thanks for the reply, and I’m glad Netlify will be fine. But it doesn’t solve my problem of the site being overwhelmed with spam requests triggering the “Next.js Server Handler” function. If I don’t stop that, all of my Netlify sites will be taken down within a few days.

I’m having the same problem as the folks in this other thread from 2023.

My site is just a single page site which could be static, so I tried adding this to my next.config.js:

const nextConfig = {
  output: 'export',
};

I also created a custom netlify.toml for my project like this:

[build]
command = "npm run build"
publish = ".next"

And set an environment variable on the Netlify site:

NETLIFY_NEXT_PLUGIN_SKIP="true"

The “Next.js Server Handler” is still there in the function logs. Is that expected?? I don’t know why a server function is created when I turned off the plugin and created a static site.

The serverless function is still being called when I go to a non-existant URL on the site, so it doesn’t seem like the problem is resolved. I fully expect the bot to return once I leave the site on for awhile.

The OP in that other thread worked around the problem with redirects. Based on the Netlify docs, I tried setting a custom 404 page:

netlify.toml

[[redirects]]
    from = "/*"
    to = "/my404.html"
    status = 404

pages/my404.js

export default function Custom404() {
  return <h1>404 - Page Not Found</h1>;
}

However, this page isn’t displaying when the user’s URL isn’t found, it’s still the standard NextJS one. And, of course, the serverless function is still being called. So what is the solution? I’m very confused how this can be a problem with something that’s supposed to be an SSG site.

As suggested in the other thread, I could attempt to block paths with individual redirect rules… but I don’t know what any of the paths are, since the function log doesn’t include the path which generated the function call. :face_with_rolling_eyes: Would be interested to learn how to find out what these failed URL paths are.

Update: Just to clarify, all of the above is after I’ve updated the site to NextJS 15.2.1.

This is a problem created by Next.js. There’s no SSG site anymore, read:

As for:

That should produce a static site and Next Runtime correctly supports it: opennextjs-netlify/src/index.ts at main · opennextjs/opennextjs-netlify. So if you’re still seeing the Handler function, that’s unexpected.

But again, the above is only true for Runtime v5.

Thanks for the further info. I found this in the Netlify docs:

For apps that use next export to generate static HTML, set the NETLIFY_NEXT_PLUGIN_SKIP environment variable to true.

The typical build settings are as follows. They differ depending on how your site is generated.

  • For apps that use static HTML export:
  • Build command: next build && next export
  • Publish directory: out

However, when I tried that, I get this error:

next export has been removed in favor of ‘output: export’ in next.config.js.

And the out directory also causes a Netlify build failure. Indeed, there is no out directory in my site’s “Deploy file browser.”

Are there more up-to-date instructions on deploying a static site on Netlify?

6:12:00 PM:   Error message
6:12:00 PM:   Error: Your publish directory was not found at: /opt/build/repo/out. Please check your build settings
6:12:00 PM: ​
6:12:00 PM:   Plugin details
6:12:00 PM:   Package:        @netlify/plugin-nextjs
6:12:00 PM:   Version:        5.9.4
6:12:00 PM:   Repository:     git+https://github.com/opennextjs/opennextjs-netlify.git
6:12:00 PM:   npm link:       https://www.npmjs.com/package/@netlify/plugin-nextjs
6:12:00 PM:   Report issues:  https://github.com/opennextjs/opennextjs-netlify/issues
6:12:00 PM: ​
6:12:00 PM:   Error location
6:12:00 PM:   In "onBuild" event in "@netlify/plugin-nextjs" from Netlify app
6:12:00 PM: ​
6:12:00 PM:   Resolved config
6:12:00 PM:   build:
6:12:00 PM:     command: npm run build
6:12:00 PM:     commandOrigin: config
6:12:00 PM:     environment:
6:12:00 PM:       - NETLIFY_NEXT_PLUGIN_SKIP
6:12:00 PM:       - NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN
6:12:00 PM:     publish: /opt/build/repo/out
6:12:00 PM:     publishOrigin: config
6:12:00 PM:   plugins:
6:12:00 PM:     - inputs: {}
6:12:00 PM:       origin: ui
6:12:00 PM:       package: '@netlify/plugin-nextjs'

I’m wondering if deploying from .next is what’s leading Netlify to assume that I want the full NextJS SSR experience instead of just static HTML/JS.

OK, I’ve worked out what was wrong with the static site approach. My next.config.js looked like this:

// Wrong!
const nextConfig = {
  output: 'export',
};

module.exports = {
  reactStrictMode: true,

  // output: 'export' // Needs to be here instead

  webpack: (config) => {
    config.module.rules.push({
      test: /\.geojson$/,
      use: ["json-loader"]
    });

    return config
  },
};

I was creating two different sets of config options and then only exporting the second one. So my site wasn’t static at all, which is why out was never produced. So I put the setting in the right place, and then also added images: { unoptimized: true },.

Now, running next build generates the out directory as expected. I then removed the netlify.toml (which I actually didn’t need) and Netlify built and deployed the static site correctly. And no more “Next.js Server Handler” function, since the site is static.