In a perfect world, at least every MAJOR EOL jQuery release line would have a security-patched release. "Major" refers to the meaning of the term in SemVer, thus releases that have breaking changes. The goal is to provide a patched version of jQuery for all major release lines to provide a path of least resistance for all downstream users to upgrade to a secure version jQuery with no (or minimal) breaking changes.
Important
*CVE-2015-9251 is not reproducible in 1.2.6
and 1.3.2
Important
CVE-2020-23064 is reproducible in all versions, but our understanding is that it is a duplicate of CVE-2020-11023
Note
The 3.x release line is currently supported by jQuery, so we have no need to provide patched versions of 3.x at this time. jQuery 3.5 introduced a breaking change, but it was necessary to fix CVE-2020-11022 and CVE-2020-11023. However, since these vulnerabilities are present in virtually all versions of jQuery, there would be no value in providing a patched version of 3.4 as it would need to include that breaking change anyway.
For one reason or another, various security issues have not been fixed or backported in older official jQuery release lines.
The presence of unpatched jQuery in a project does not necessarily mean there is an exploitable vector in that project. When analyzing a vulnerability, the project may find an exploitable vector and patch that vulnerability in their code without upgrading jQuery. Or, they may find that no exploitable vector exists. In both cases, arguably, there is no immediate compelling need to upgrade jQuery. The risk, of course, is that a future change may introduce an exploitable vector, so it is best to upgrade anyway to eliminate this possibility.
While some projects may be able to upgrade to newer/supported jQuery versions, this is often non-trivial in other projects, particularly with large, long-lived projects due to breaking changes.
The jQuery project spawned a large ecosystem, with myriad plugins and libraries that also depend on jQuery. In many cases, those projects have been abandoned, so when a jQuery upgrade is required, it leaves downstream users no choice but to either effectively adopt the projects and take on the maintenance burden, or replace them altogether; both of those options can be prohibitively expensive.
If we can patch an old version of jQuery without too much trouble, it has the potential to save downstream users a lot of time and effort AND help secure the web. If we can do that, why not make this publicly available? Some projects and organizations are already using their own private patched versions of jQuery to solve this problem.
In some cases, it may be unavoidable that a security fix involves a breaking change. Nonetheless, the patched version should only need to include those breaking changes that are absolutely necessary to fix the security issue(s) and nothing more. While this still potentially requires code changes from downstream users, it may be far less than the changes that would be required by a more significant upgrade.
- All CVEs for the release MUST be patched
- Wherever possible, reuse the existing patch code from patched official jQuery releases
- All existing passing tests MUST pass
- Additional unit/integration test coverage as needed to account for the changes
- A/B end-to-end acceptance tests against the unpatched and patched versions for all CVEs
Important
To run the jQuery tests or to build jQuery, you need to checkout the branch of the version you are interested in, e.g. 1.6.5-sec
, from the jQuery Security Patches repo.
To run the A/B CVE tests, use this repo.
- Make
- Node.js
- Node v20, the current LTS version at the time of this writing is the version used, although you may be successful with other versions
- You'll need to install php 5.6 -- a newer version of php will probably work as well, but we used 5.6
- For Macs, We recommend using homebrew-php
- For jQuery versions up to and including 1.8.3 / 1.8.4-sec, you can get away with the built-in php dev server along with some symlinks. For later versions of jQuery, you'll need to have (or install) a proper server.
- The path of least resistance is to use
nginx
: brew install nginx
- The path of least resistance is to use
- Checkout the
1.2.6
or1.2.7-sec
branch - Run
make
from the root folder of the repo - Open
/tests/index.html
in your browser
- Checkout the
1.3.2
or1.3.3-sec
branch - Run
make test
from the root folder of the repo - Open
/tests/index.html
in your browser
- Checkout the
1.4.4
or1.4.5-sec
branch - From the root folder of the repo:
git clone git@github.com:jquery/sizzle.git --depth=1 src/sizzle
cd src/sizzle
git fetch --tags
- Get corresponding sizzle branch for this jQuery version/release:
git checkout 1.4.4
cd ../..
git clone git@github.com:qunitjs/qunit.git --depth=1 test/qunit
cd test/qunit
- Get the closest QUnit commit to the jQuery version/release:
git checkout 25e4489a5f280e8f0a22ca99ecb401338bb75308
cd ..
make jquery
- Follow the instructions in Running a web server
- if using the php dev server, create a symlink to
/src
from the/test
folder:cd test && ln -s ../src src
- if using the php dev server, create a symlink to
- Checkout the
1.5.2
or1.5.3-sec
branch - From the root folder of the repo:
git submodule update --recursive
- if you get errors updating submodules, you may need to search for
[submodule
and update git:// urls to https://
- if you get errors updating submodules, you may need to search for
make
- Follow the instructions in Running a web server
- if using the php dev server, create a symlink to
/src
from the/test
folder:cd test && ln -s ../src src
- if using the php dev server, create a symlink to
- Checkout the
1.6.4
or1.6.5-sec
branch - From the root folder of the repo:
git submodule update --recursive
- if you get errors updating submodules, you may need to search for
[submodule
and update git:// urls to https://
- if you get errors updating submodules, you may need to search for
- Follow the instructions in Running a web server
- Checkout the
1.7.2
or1.7.3-sec
branch - From the root folder of the repo:
git submodule update --recursive
- if you get errors updating submodules, you may need to search for
[submodule
and update git:// urls to https://
- if you get errors updating submodules, you may need to search for
- Follow the instructions in Running a web server
- Checkout the
1.8.3
or1.8.4-sec
branch - From the root folder of the repo:
git submodule update --recursive
- If you get errors updating submodules, you may need to search for
[submodule
and update git:// urls to https://
- If you get errors updating submodules, you may need to search for
- Globally install the requisite ancient version of grunt:
npm i grunt@0.3.9 -g
npm i
- Modify the
grunt.js
file- Remove
submodules
from the default grunt task - Remove
compare_size
from default grunt task
- Remove
- Run
grunt
- You should get errors about
path.existsSync()
innode_modules/grunt/lib/util/findup.js
and innode_modules/grunt/bin/grunt
- Modify both files to
require('fs')
and changepath.existsSync()
tofs.existsSync()
- Modify both files to
- You should get errors about
- Run
grunt
- It should work now
- Follow the instructions in Running a web server
- if using the php dev server, create a symlink to
/dist
from the/test
folder:cd test && ln -s ../dist dist
- if using the php dev server, create a symlink to
- Checkout the
1.12.4
or1.12.5-sec
branch - From the root folder of the repo:
npm i -g grunt-cli
- Add the following
overrides
object topackage.json
: -"overrides": { "graceful-fs": "^4.2.11" }
- Run
grunt
- If you get an error about
os.tmpDir()
innode_modules/npm/node_modules/osenv/osenv.js
then:- Modify that file to call
os.tmpdir()
instead ofos.tmpDir()
- Modify that file to call
grunt
should work now
- Follow the instructions in Running a web server
- Checkout the
2.2.4
or2.2.5-sec
branch - From the root folder of the repo:
npm i -g grunt-cli
- Run
grunt
- Follow the instructions in Running a web server
it is preferable to use NGINX instead of the php dev server and it is required for version 1.12 and up
- A pre-configured
nginx
configuration file (nginx.conf
) is in the root of the repo- Modify the first two paths near the top of the file to suit your filesystem
- In a separate terminal window, run
nginx
, replacing the paths to suit your filesystem:/path/to/nginx/bin/nginx -c /path/to/nginx.conf -g daemon\ off\;
- From the
test/
folder of the repo:brew services start php@5.6
- Open
localhost/tests
in your browser - When you are finished:
CTRL+C
in the terminal where you are runningnginx
brew services stop php@5.6
- From the root folder of the repo:
php -S localhost:8000 -t test
- Open
localhost:8000/tests
in your browser
Tests run on every push in CI via GitHub workflow
You can run the A/B tests locally in CI mode or manually in the browser
- Checkout the
main
branch - Run
nom test
in/security/test
- Rejoice!
- Checkout the
main
branch - Run
nom run serve
in/security/test
- Open
localhost:3333
in your browser of choice - Select the jQuery version you are interested in
- All CVEs are reproduced automatically, but you can trigger them again by clicking their respective buttons
- Check the
Patched
checkbox to load the patched version of the jQuery version you selected - An attempt is made to trigger all CVEs automatically, but you can attempt to trigger them again by clicking their respective buttons
- Rejoice!
Ultimately, our hope is that these patched versions can be approved and accepted by the official jQuery project/maintainers and deployed as official jQuery releases.