Security measures you miss out when you are using native <img /> tag in Next.js


This is a short rundown on all the security measures and optimizations that you might miss out on if you go with the native html <img />
tag instead of <Image />
component from Next.js.
The usual suspects: Cross-Site Scripting (XSS attacks) and Denial-of-Service (DoS) Attacks
While it’s common to assume that XSS attacks occur in text-based inputs, it can also be exploited via image URLs or by embedding scripts within image files.
Embedded scripts within image files sounds like a “there is no way I can fight that” problem, but one very cool solution that I randomly stumbled upon is to
Consider inserting some random noise into the image. For instance, you might loop over all the pixels, and for each of the three intensities (corresponding to RGB) for that pixel, randomly choose among adding 1, subtracting 1, or leaving that intensity value alone. This introduces a tiny bit of noise into the image, but hopefully not enough to be noticeable to viewers. And, if you are lucky, it may make some attacks less likely to succeed, because the attacker cannot fully predict the result of the transformation.
Designers reading this, I know you will pull your hair out if images are messed with like this. Devs, make sure they are always in the loop if there are any subtle additions like this.
I got curious if this could work and made a v0 prototype, it is so cool that we can experiment with these things in a matter of seconds these days. Check it out:
https://v0.dev/chat/06Lglf4CkGr
All the sites I referred to for this issue and recommend taking a look at:
With the case of DoS Attacks, Attackers can flood a server with a high volume of requests for image files, particularly large ones, or send malformed image data that consumes excessive server resources, ultimately leading to service disruption for legitimate users. Without proper preventative measures, such as rate limiting and adequate resource management, an application can become vulnerable to such attacks simply by displaying images. All of these, preventable by using the <Image /> component instead.
Content Sniffing Attacks
Browsers sometimes attempt to determine the file type of a resource by examining its content rather than relying solely on the Content-Type
header provided by the server. This behavior, intended to improve user experience when servers misconfigure MIME types, can be exploited by attackers who disguise malicious code as an image file. If a browser incorrectly identifies the file as an executable type, it might execute the harmful content. To prevent this, servers should send the X-Content-Type-Options: nosniff
header, which instructs browsers to rely only on the declared Content-Type
. The risk lies in the fact that simply checking the file extension of an image URL is insufficient, as the actual content might be something entirely different, posing a security threat.
SSRF attacks & Frame injection
Got a Server-side logic to process an image url fed by the user? there is a cool sounding attack called Server-Side Request Forgery which can retrieve resources and sniff around your database / network. More information here.
In-fact, there has been a vulnerability in the past. The _next/image
API, which is the <Image />. component, was found to be vulnerable to SSRF in versions prior to 14.1.1. This vulnerability allowed attackers to manipulate the Host
header and redirect requests internally, enabling unauthorized access to internal services or data.
For example, if an attacker crafts a URL like:
https://example.com/_next/image?url=http://internal-service.local/resource
Next.js might fetch and process this URL, exposing internal resources.
On to the other subject, Frame injection occurs when an attacker embeds malicious content within an iframe or similar elements, potentially tricking users into interacting with harmful interfaces or stealing sensitive information. While <img>
tags themselves do not directly enable frame injection, they can be exploited indirectly if combined with vulnerabilities in server-side image processing APIs like _next/image
. You can see how these two can go hand-in-hand.
Bridging the gap: Manual Security Implementation for Native <img>
Tag
If you have no option but to use the native tag for some reason, then certain things can be done to provide basic security features
Robust image URL sanitization and validation. Here’s a cool post that expands more on that.
Leverage CSP rules. The
img-src
directive within the CSP header allows developers to control the origins from which images can be loaded.Cross-Origin Resource Sharing (CORS) headers can be used by servers to explicitly allow controlled access to their resources, including images, from different origins when necessary. Modern browsers also implement defenses against content sniffing attacks, especially when the server provides accurate
Content-Type
headers and theX-Content-Type-Options: nosniff
header.Pray that the security gods are with you 🙏
Credits:
Gemini and Perplexity were used for research and writing this article.
Vaishnav who got me thinking about the differences between native img tags and Image component from Next.js and that led me to write about this topic.
Subscribe to my newsletter
Read articles from Shreyas directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
