How Attackers Hide JavaScript in JPEG Comments
Attackers frequently exploit the binary structure of image formats to
hide malicious JavaScript inside JPEG comment markers, creating
structurally valid images that double as payload carriers. This
technique leverages the COM marker defined by the JPEG
specification to store arbitrary text without breaking the visual
integrity of the graphic. While image tags do not execute this code
natively, attackers chain this stealthy injection method with secondary
vulnerabilities—such as polyglot execution, cross-site scripting (XSS),
or metadata-parsing flaws—to achieve client-side code execution.
The Structure of the JPEG COM Marker
JPEG files consist of a sequence of segments, each beginning with a
two-byte marker starting with 0xFF. The comment marker,
designated as COM, uses the byte sequence
0xFF 0xFE.
Immediately following the 0xFF 0xFE marker is a two-byte
value specifying the length of the comment payload (including the two
bytes of the length field itself). Following the length indicator, the
JPEG standard allows arbitrary binary or ASCII data up to 65,535 bytes.
Image decoders parse this segment, recognize the length, and safely skip
over the content to continue rendering the visual image data.
The Embedding Process
To inject a payload into the comment field, an attacker carries out a sequence of binary modifications:
- Locating or Appending the Marker: An attacker opens
a valid JPEG file using a hex editor or an automated script (such as a
Python script utilizing
struct). They search for an existing0xFF 0xFEsequence or identify the Start of Image marker (0xFF 0xD8) to insert a new comment block immediately after it. - Calculating Segment Length: The attacker determines the byte length of their JavaScript payload, adds two bytes to account for the length field itself, and converts this value into a two-byte, big-endian integer.
- Injecting the Payload: The attacker writes the
0xFF 0xFEmarker, inserts the calculated length bytes, and appends the raw JavaScript code (for example:/* */=alert(1);). - Finalizing the File: The rest of the image data
remains untouched. Because the image rendering engine only looks for
visual markers (such as Start of Scan,
0xFF 0xDA), the embedded script does not trigger parsing errors or corrupt the visual output.
Execution Mechanisms
Placing JavaScript inside a JPEG does not automatically trigger
execution when loaded via standard
<img src="image.jpg"> tags. Attackers rely on
specific delivery contexts to run the payload:
- Polyglot Script Execution: An attacker crafts the
file so it is simultaneously a valid JPEG and valid JavaScript. By
carefully placing comment indicators (like
/*and*/) around the binary headers, the attacker can load the image via a script tag:<script src="avatar.jpg"></script>. The browser's JavaScript engine parses the entire image file as a script, ignores the binary portions wrapped in comments, and executes the payload stored in theCOMsegment. - MIME Sniffing and Misconfiguration: If a web
application allows users to upload JPEG files and subsequently serves
them with missing or incorrect headers (such as
text/htmlinstead ofimage/jpeg), a browser with MIME-sniffing enabled may interpret the file as an HTML/JavaScript document rather than an image. - Client-Side EXIF and Metadata Parsers: Web
applications often use client-side JavaScript libraries to extract
metadata from uploaded images. If an application extracts the
COMfield and writes its contents directly to the DOM using insecure methods (such asinnerHTML), the embedded JavaScript executes in the context of the user's session.
Mitigation Strategies
Defending against malicious metadata embedding requires proactive image sanitization and strict HTTP header enforcement:
- Image Re-encoding: Applications should process all uploaded images using server-side graphics libraries (such as ImageMagick or Sharp) to strip out all non-essential metadata and re-encode the pixel data before saving.
- Header Enforcement: Ensure all served media files
include the explicit, correct MIME type
(
Content-Type: image/jpeg) alongside theX-Content-Type-Options: nosniffheader to prevent browsers from interpreting image files as executable scripts. - Content Security Policy (CSP): Implement strict CSP
directives, such as limiting
script-srcto trusted domains and disallowingunsafe-inline, which blocks the browser from executing scripts originating from arbitrary file formats.