Closed Bug 1940027 (CVE-2025-1936) Opened 9 months ago Closed 9 months ago

jar: URL with embedded null ("%00") can be used to make us misinterpret a file's MIME type

Categories

(Core :: Networking: JAR, defect, P2)

Firefox 133
defect

Tracking

()

VERIFIED FIXED
136 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr128 136+ verified
firefox134 --- wontfix
firefox135 - wontfix
firefox136 + verified

People

(Reporter: sdev81300, Assigned: valentin)

Details

(Keywords: csectype-sop, reporter-external, sec-low, Whiteboard: [necko-triaged][necko-priority-queue][adv-main136+][adv-esr128.8+])

Attachments

(9 files, 2 obsolete files)

Attached image XSS_Using_Jar_File.png

Firefox for Android

Steps to reproduce:

A vulnerability in the jar: protocol parser of Mozilla Firefox allows filename and extension spoofing and MIME type manipulation leads to XSS when a null byte (%00) is included in the entry name of a JAR archive. This can result in malicious code execution, such as triggering JavaScript payloads embedded in image files by spoofing the file extension and MIME type.

[+] Screenshot Attached below , I can only attach one screenshot, if need more details please reach me out!!

Actual results:

Create a Malicious File:

  1. Embed a JavaScript payload in the EXIF data of an image file (e.g., hacker.png) using the Exiftool like so : exiftool -Comment=<script>alert('XSS By Surya Dev Singh')</script>" hacker.png

  2. Place the image (hacker.png) file in one folder (lets say hacker) and archive it to zip (jar files are basically zip file only so you can rename the generated zip file to something like hacker.ja)

  3. Try to load the hacker.png file using the normally using the jar protocol : jar:file:///C:/Users/Username/Desktop/hacker.ja!/hacker/test2/hacker.png
    It will load the image normally.

  4. But if you modify the URL by injecting Null Byte , it will terminate the "AUTF8String JAREntry" entry definition from the code . the modified URL would look like this :
    jar:file:///C:/Users/Z004WREN/OneDrive%20-%20Siemens%20Healthineers/Desktop/hacker.ja!/hacker/test2/hacker.png%00.html

  5. This will Trigger the XSS payload that we have store in Exif comment data.

  6. Now we can use this Null Byte Behavior with some slide modification to change the file name and its extension . which further means that we can change the mime type of the file . Thus will trigger an user to run the malicious file as non malicious file.

  7. to do that we need to to add "://<custom_filename>" after the null byte termination. like so :

jar:file:///C:/Users/Z004WREN/OneDrive%20-%20Siemens%20Healthineers/Desktop/hacker.ja!/hacker/test2/hacker.png%00://definitely_not_a_hacker_file.exe

This will download the hacker.png file as "definitely_not_a_hacker_file.exe" with executable extension.


All this behavior has been trigger due to the vulnerable code base in mozilla :
The two classes GetJARFile and GetJAREntry makes heavy use of nsCString (likely a Mozilla-specific wrapper around std::string or a similar container) and other string types. Functions that process strings could be vulnerable if the null byte is mishandled. Here’s a potential scenario:

In SetSpecWithBase(const nsACString& aSpec, nsIURI* aBaseURL), the code likely constructs and manipulates URLs. If the aSpec string contains a null byte in an unexpected location, the nsIJARURIMutator function is then not able to handle the input that's coming from the GetJAREntry . it might cause string manipulation functions (e.g., strlen, strcpy, strcat) to terminate prematurely or lead to buffer overflows/underflows.

The methods that handle strings (such as SetPathQueryRef, SetHostPort, SetRef) could all be susceptible to this issue if they don't handle strings properly

Here are link to codebase :

https://searchfox.org/mozilla-central/source/__GENERATED__/dist/include/nsIJARURI.h#35

Expected results:

what should have happened :

The jar: protocol parser should correctly handle null bytes (\0) in filenames, preventing filename and extension spoofing.

The MIME type of the file should remain consistent with its actual content and extension, disallowing manipulations.

Files within JAR archives should be securely validated and sanitized to prevent execution of embedded scripts.

No JavaScript payload embedded in non-HTML files should execute, even with manipulated MIME types.

Group: firefox-core-security → network-core-security
Component: Untriaged → Networking: JAR
Product: Firefox → Core

Valentin, could you confirm whether the bug is easily exploitable?

Flags: needinfo?(valentin.gosu)

Since Firefox internally uses this jar: protocol to load extensions.

  • any attacker could use extension to deliver malicious file by filename and extension spoofing by abusing the mime type described above
  • can abuse the above describe code execution method to run arbitrary JavaScript code.

Hi @smayya ,
I reported this bug here instead of Hackerone. I hope its still falls under Security Bug Bounty Program and can be assigned CVE ID to this.
Can you give your input on this ?

Thank You ☺ !!

(In reply to Surya Dev Singh from comment #6)

Hi @smayya ,
I reported this bug here instead of Hackerone. I hope its still falls under Security Bug Bounty Program and can be assigned CVE ID to this.

I think bug bounties are submitted to bugzilla are just fine. But note this item in https://www.mozilla.org/en-US/security/client-bug-bounty/#claiming-a-bounty

If you have filed the bug directly in Bugzilla without using the Bugzilla client bug bounty form, please immediately notify the Mozilla Security Group by email to security@mozilla.org and include the number of the bug you filed and a mention that you are submitting it for bounty consideration. Do not send the actual vulnerability via email.

(In reply to Sunil Mayya from comment #4)

Valentin, could you confirm whether the bug is easily exploitable?

I haven't yet tested if this actually works, but as far as I understand we need a webextension/jar containing an image with a comment that embeds JS code, or an executable file embeded in the JAR as an image.
While these could make it possible to get around some of the AMO checks and include some risky code in your exension, as far as I can tell the webextension author already has the ability to run arbitrary JS code included in the extension.

@Surya Dev Singh, is there anything that a malicious extension could achieve by exploiting this bug that it can't already do?

Flags: needinfo?(valentin.gosu) → needinfo?(sdev81300)

This potential vulnerability stems from how Firefox handles the JAR protocol, allowing a malicious web extension to embed risky code that could lead to arbitrary code execution. By embedding JavaScript in image comments or including an executable disguised as an image file within the JAR, the extension can exploit null byte injection and how the JAR protocol parser processes file paths and embedded data.

While a malicious extension author already has the ability to run arbitrary JavaScript within the extension, this vulnerability offers additional exploitation possibilities:

  • Stealthy Malware Delivery : An attacker could manipulate file names and extensions which auto downloads non common files like exe, enabling malware to be delivered as a seemingly harmless file, thus increasing the chances of user interaction.

  • Exploitation Vector : This flaw allows JavaScript code to be executed from non-JavaScript files, such as innocent-looking image or text files, processed as part of the JAR. Despite appearing benign, these files can execute malicious code behind the scenes.

The core issue lies in the vulnerability of Firefox’s JAR protocol parser, not the extension itself. This makes the bug particularly impactful, opening up new avenues for exploitation and broadening the attack surface. Given its potential severity, this flaw is a strong candidate for a bug bounty.

Valentine, please if possible can you check the POC provided in the "JAR:" protocol itself and let me know if it works as expected."

Thank You !!

Flags: needinfo?(sdev81300) → needinfo?(valentin.gosu)
Flags: sec-bounty?

Valentine, please if possible can you check the POC provided in the "JAR:" protocol itself and let me know if it works as expected."

I don't see a PoC anywhere we can check, only a bunch of screenshot attachments? Screenshots are not proofs of anything when they can be so easily faked. Can you please attach one for Valentin to check

Flags: needinfo?(valentin.gosu) → needinfo?(sdev81300)

[trimmed unnecessary quote of comment 0 -dv]

Hello Team !!

Thank you for your reply !! Here is the full step by step POC that I have given, and screenshots are also attached for the same .
any person responsible to triage of the bug can easily use this step to reproduce the bug described.
This is what standard POC look like. but if you prefer it in some video form I can do it. I understand that screenshots can be faked, but this is what standard triage process goes in checking the validity of the POC I have given.

This a security bug should be triage and responded immediately to reduce the risk of its exposure so that a CVE id can be assign to it, since I have not reported it on hackerone. The Mozilla team can directly take a look at it here itself or can ask the team that review the bugs from the Hackerone mozilla bug bounty ( if there is a different team) . looking forward into this !!

Thank You !!

Flags: needinfo?(valentin.gosu)
Flags: needinfo?(sdev81300)
Flags: needinfo?(dveditz)

Please let me know if you need any further input from my end , I would be really happy to secure the Mozilla software.
Thank You

We do NOT mean a video when we say PoC. A video is the same type of evidence as a screenshot. They can be useful for understanding, but almost never detailed enough on their own to replace an actual PoC.

Your "steps to reproduce" are just that, steps to reproduce. They are instructions for us to build our own PoC but not themselves the PoC. For a web site vulnerability "user actions" might be the full explanation of a vulnerability, But for a client bug (especially one like this dealing with specifically prepared binary files) the PoC is the set of files you deliver to a user, and how, so that they trigger the problem.

We certainly can follow your steps and create a hacked .jar file for ourselves, but that extra time requirement will tend to move your bug to the bottom of the pile of bugs to investigate. Presumably you already have the hacked .jar file used to make the screenshots so it would be easy to attach to the bug, and that would save us a lot of time. As a secondary benefit it makes sure we don't misinterpret one of the steps, or can't reproduce because you forgot to mention some modification. In this case the steps are straightforward and those outcomes unlikely, but that's one of the reasons we like to get the PoC from the reporter themselves.

As far as we know the jar: protocol is not usable from web content and therefore isn't something users will stumble upon on their own so the impact appears limited. We might be wrong—many vulnerabilities from from incorrect assumptions—and that, too, is something an actual PoC could demonstrate.

I completely understand the concept of the name hack with the embedded null. Something that reads or displays the name as a "C String" might show the .png extension, and internally Firefox "knows" the .jar said "the name is XX characters long" and therefore .html is the "real" extension at the end. Where my understanding is failing is who this is spoofing and how? In a hypothetical attack

  • who made the jar file? how does the user get it?
  • If the user takes an action and suddenly gets a "definitely_not_a_hacker_file.exe" download, why would the user think or expect it to be anything other than a downloaded executable? where it came from is all opaque to a user, right? Why would they even think it was supposed to be a .png?

Like in your first screenshot a user opens a random URL, normally a random URL can run JavaScript -- that's not a surprise. It even says ".html" on the end very clearly in that screenshot. Of course you can make the name longer to hide that, but then you'd also likely hide the ".png" that you're apparently trying to fool the user with -- you have no idea what the victim's window-size or resolution is going to be.

OK, now the 3rd screenshot has no null. Are you saying that is the same .jar file as the other screenshots? Does the .jar have two different files in it, one with the null and one not? Or is the "0x00" is only in the URL used to access it and not actually in the .jar itself? Your initial description said "leads to XSS when a null byte (%00) is included in the entry name of a JAR archive" and you link to code for JAREntry so I assumed the null was in the zip archive directory entry.

Flags: needinfo?(dveditz) → needinfo?(sdev81300)

OK, the null is in the URL, not the .jar/.zip itself. compare: resource:///chrome.manifest with resource:///chrome.manifest%00.html (you will have to copy those URLs and paste them in a new window—web content can't link to resource: urls)

That resource: URL is equivalent to a jar: url into your install directory, so in my case you can do the same with jar:file:///Applications/Firefox Nightly.app/Contents/Resources/browser/omni.ja!/chrome.manifest%00.html. The easiest way to get that is to "typo" the path (chrome.manifes) and then copy the jar URL from the error page and put the 't' back on the end.

This is definitely a bug in the jar: URL parser which should treat a null/%00 as invalid. Someone could hack a zip archive to put a null in a filename in the directory entry, but you couldn't unzip that entry into a filename and I see no need for Gecko to support such an esoteric edge case with the jar: protocol.

The reporter is correct that a manipulated jar: URL could use this trick to force Firefox to interpret an entry in a zip archive as a different type than its filename suggests. How the victim gets the hacked .zip archive or the malicious URL to it is apparently an exercise for the reader.

Without a PoC there's no evidence this could actually be used in a "spoofing" or "XSS" attack. The jar: protocol is an internal mechanism.

Summary: Null Byte Injection in jar: protocol can lead to file name and extension spoofing , Mime Type Confusion, and XSS → jar: URL with embedded null ("%00") can be used to make us misinterpret a file's MIME type
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: sec-low

Definitely something we ought to fix.
Unclear right now if it also affects moz-extension URLs

Assignee: nobody → valentin.gosu
Severity: -- → S3
Flags: needinfo?(valentin.gosu)
Priority: -- → P2
Whiteboard: [necko-triaged][necko-priority-next]

Some checks are being going on , will update this thread as we have something !!
Thank you

Flags: needinfo?(sdev81300)

This also affects moz-extension:-URLs because they internally resolve to jar:-URLs. TL;DR of below: the worst that can happen here is misleading reviewers of extension code.

Unlike the other URLs here, moz-extension:-URLs can be linked from the web if the extension opts in by specifying an entry in web_accessible_resources. This list can contain explicit file names or wildcards. To exploit this bug at all, a wildcard must be used. Moreover extensions have a strict CSP that only allows its own scripts and disallows external and inline scripts - this mitigation has to be bypassed to create a successful exploit targeting victim extensions.

The most realistic attack scenario targeting victim extensions that I can imagine is as follows:

  • a victim extension contains a non-HTML file that, when rendered as HTML, embeds a <script> element (statically in the source, can be a relative path) that references a vulnerable JS resource within the same extension.
    • The non-HTML file doing something dangerous when rendered as HTML scenario itself is unlikely. The most realistic scenario that I can imagine is a JS file that embeds a HTML template or code comment with HTML.
    • By vulnerable JS resource, I mean an extension's custom JS code that does not expect execution triggered by a third party.
  • An attacker somehow discovers the extension's unique moz-extension:-URL and loads moz-extension://uuidhere/file.js%00.html. Now it manages to invoke extension-defined functionality, unexpectedly.

The above scenario is not very realistic.

Another attack scenario is on the verification side:

The latter scenario is a realistic way to reduce the effectiveness of extension review process.

To verify that moz-extension:-URLs are vulnerable at all by this bug, follow the following steps:

  1. Visit about:debugging and look up the moz-extension:-URL of the built-in webcompat extension.
  2. Paste this URL in the address bar, with TODO_REPLACE_THIS replaced with the actual uuid from step 1: moz-extension://TODO_REPLACE_THIS/shims/instagram-embed.js%00.html
  3. Observe that the JS file is rendered as HTML, notably by this <img tag being rendered as a (broken) image: https://searchfox.org/mozilla-central/rev/9f9fa5d2cb72b12ac7e168b7f6ee9820f63291e9/browser/extensions/webcompat/shims/instagram-embed.js#143
Whiteboard: [necko-triaged][necko-priority-next] → [necko-triaged][necko-priority-queue]

bug explainer

In nsJARChannel::LookupFile we unescape the filename of the file we're trying to load, while nsZipArchive::GetItem takes a char* filename argument, and computes the length based by calling strlen which is affected by embedded nulls.

nsExternalHelperAppService::GetTypeFromExtension works correctly in this case - even for URLs with percent encoded nulls the extension like .js%00.html the extension should be the last one.

The problem in this case is that the URL and JAR entry we were loading didn't match.
The solution in this case was to update nsZipArchive::GetItem, nsZipItemPtr_base::nsZipItemPtr_base and mozilla::FileLocation::FileLocation to pass the filename through nsACString instead.

The test fails without the patch applied, and passes with the patch applied.
I've also manually checked that jar URLs with embedded nulls no longer work.

Pushed by valentin.gosu@gmail.com: https://hg.mozilla.org/integration/autoland/rev/2da7039ab3d2 Use nsACString in jar code r=necko-reviewers,kershaw
Group: network-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 9 months ago
Resolution: --- → FIXED
Target Milestone: --- → 136 Branch

The patch landed in nightly and beta is affected.
:valentin, is this bug important enough to require an uplift?

  • If yes, please nominate the patch for beta approval.
  • If no, please set status-firefox135 to wontfix.

For more information, please visit BugBot documentation.

Flags: needinfo?(valentin.gosu)
Attachment #9460483 - Flags: approval-mozilla-beta?

beta Uplift Approval Request

  • User impact if declined: Resources could be loaded from webextensions or other JAR resources with the wrong content-type. This could lead to the execution of comment embedded in an images' metadata as javascript if %00.js were appended to the image URL.
  • Code covered by automated testing: yes
  • Fix verified in Nightly: yes
  • Needs manual QE test: yes
  • Steps to reproduce for manual QE testing: Load jar:file:///[path_to_archive]!/resource.txt - This should load. Make sure that appending %00.js to the path makes the load fail.
  • Risk associated with taking this patch: low
  • Explanation of risk level: This patch attempts to make minimal behaviour changes to Firefox. It just changes the argument types of several methods to use nsACString instead of char*. The result is that percent unescaping the string should will pass the entire string to the consumer, and we will match the full path against the JAR resource, not just the characters before %00.
  • String changes made/needed: none
  • Is Android affected?: yes
Flags: qe-verify+
QA Whiteboard: [qa-triaged]
Attachment #9460483 - Attachment is obsolete: true
Attachment #9460483 - Flags: approval-mozilla-beta? → approval-mozilla-beta-
Flags: needinfo?(valentin.gosu)
Attached image image.png

Hello. I have reproduced the issue with firefox 135.0a1 (2025-01-05) on Windows 10x64 by following the next steps:

  1. Created a test.jar file containing resource.txt (with random text) using jar cf test.jar resource.txt in CMD
  2. In the Firefox URL bar load the following links:
  • jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt
  • jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00.js
  • jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00

Actual result:

  • In an affected build all links from steps 2 are loaded showing the text from step 1.
  • In a fixed build with Firefox 136.0a1 (2025-01-21) only the jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt link is loaded. The jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00.js and jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00 links are showing File not found error (see screenshot). This was tested on Windows 10x64, macOS 12 and Ubuntu 24.04.

Just to be safe is the verification correct? Is there anything else that I should verify here?

Flags: needinfo?(valentin.gosu)

Thanks, that's all right!

Status: RESOLVED → VERIFIED
Flags: needinfo?(valentin.gosu)

Thank you!

Has STR: --- → yes
QA Whiteboard: [qa-triaged]
Flags: qe-verify+

The most interesting way to abuse this we've thought of is for a malicious extension to try to slip something by our reviewers. But it's still a malicious extension that a victim ``would have to install

Flags: sec-bounty? → sec-bounty+

(In reply to Daniel Veditz [:dveditz] from comment #29)

The most interesting way to abuse this we've thought of is for a malicious extension to try to slip something by our reviewers. But it's still a malicious extension that a victim ``would have to install

I understand the extension would have to be install but this vulnerability would be running the JS code under the hood without the user knowing which is a security risk here and Thus can load Resources from WebExtensions or other JAR resources with the wrong content-type. This could lead to the execution of comment embedded in an images' metadata as JavaScript if %00.js were appended to the image URL.

From all the above discussion the conclusion comes that moz-extension are also vulnerable to this bug . as the team were able to reproduce the bug and the relevant patches have been applied , I want to know the when and how the bounty process would be initiated.

Seems like my PGP was not set up for secure group email communication, I have done it now.
I am not sure weather the communication regarding the bounty have been made. if not, you can send me to my Email to initiate the bounty process since the PGP keys are now set.

Thank you Team !!

Hello Team,

I wanted to get the CVE ID assigned to this bug, when can i expect the public information be disclosed ? so that I can apply for CVE MITRE to assign it a CVE.

:valentin could you add an esr128 uplift request on this?

Flags: needinfo?(valentin.gosu)
Attachment #9465386 - Flags: approval-mozilla-esr128?
Attachment #9465388 - Flags: approval-mozilla-esr128?

esr128 Uplift Approval Request

  • User impact if declined: Resources could be loaded from webextensions or other JAR resources with the wrong content-type. This could lead to the execution of comment embedded in an images' metadata as javascript if %00.js were appended to the image URL.
  • Code covered by automated testing: yes
  • Fix verified in Nightly: yes
  • Needs manual QE test: yes
  • Steps to reproduce for manual QE testing: See comment 25 and comment 26
  • Risk associated with taking this patch: low
  • Explanation of risk level: This patch attempts to make minimal behaviour changes to Firefox. It just changes the argument types of several methods to use nsACString instead of char*. The result is that percent unescaping the string should will pass the entire string to the consumer, and we will match the full path against the JAR resource, not just the characters before %00.
  • String changes made/needed: none
  • Is Android affected?: yes
Flags: qe-verify+
Flags: needinfo?(valentin.gosu)
Attachment #9465388 - Flags: approval-mozilla-esr128? → approval-mozilla-esr128+
Attachment #9465388 - Flags: approval-mozilla-esr128+ → approval-mozilla-esr128-
Attachment #9465388 - Attachment description: Bug 1940027 - Use nsACString in jar code r=#necko → Bug 1940027 - Use nsACString in jar code r=dmeehan
QA Whiteboard: [qa-triaged]
Attachment #9465388 - Flags: approval-mozilla-esr128- → approval-mozilla-esr128+
Attachment #9465386 - Attachment is obsolete: true
Attachment #9465386 - Flags: approval-mozilla-esr128? → approval-mozilla-esr128-

Verified fixed with 128.8.0esr on Windows 10x64, macOS 12 and Ubuntu 24. Same results as in comment 26.

QA Whiteboard: [qa-triaged]
Flags: qe-verify+
Whiteboard: [necko-triaged][necko-priority-queue] → [necko-triaged][necko-priority-queue][adv-main136+][adv-esr128.8+]
Attached file advisory.txt
Alias: CVE-2025-1936
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: