Magento (now Adobe Commerce) powers a significant share of the world's online stores, from small independents to large retailers processing millions of transactions. That concentration of payment card data, personal information, and stored credentials makes it one of the most persistently targeted e-commerce platforms in the wild.
The threat is not theoretical. Magecart, the name given to criminal groups that inject JavaScript skimmers into checkout pages, originated specifically as attacks against Magento-based stores, and the technique has never stopped. In 2024 alone, roughly 269 million cards were compromised across approximately 11,000 e-commerce domains, nearly a 300% increase from 2023, with Magecart-style skimming kits lowering the technical barrier for attackers significantly. The CosmicSting vulnerability (CVE-2024-34102) in Adobe Commerce and Magento enabled mass Magecart infections throughout 2024, with Sansec reporting that 75% of stores remained unpatched one week after the security fix was released.
The attack chain on a compromised Magento store typically runs: initial access via a known vulnerability, code execution or file write, JavaScript skimmer injected into the checkout page, then card data silently exfiltrated to an attacker-controlled server, often for months before detection. These attacks can go undetected for long periods, and the injected scripts piggyback on legitimate third-party tools to evade detection. The downstream consequences (PCI DSS breach notifications, card replacement costs, regulatory fines, and reputational damage) fall on merchants who were simply running an unpatched version of their platform.
This is what makes accurate version fingerprinting operationally important. Knowing that a target is running "Magento 2.4" tells you almost nothing. Knowing it is running 2.4.6-p2 tells you exactly which CVEs are in scope and whether the store was exposed during a specific exploitation window.
This vulnerability, disclosed in Adobe's APSB26-92 advisory on 2026-08-11, illustrates why version precision matters.
CVE-2026-71362 is an unauthenticated customer account takeover with a CVSS score of 9.1. Exploitation requires no administrator privileges and no user interaction, but does require a self-registered attacker account on any store that permits customer registration.
The root cause is that Magento\Customer\Controller\Account\Edit::execute() feeds the raw, attacker-controlled customer_form_data left in the session by a failed editPost into DataObjectHelper::populateWithArray(), which copies every matching key onto the customer object, including id. The object is then written back via Session::setCustomerData(), and overwriting customer_id alone makes isLoggedIn() return true as the victim. An attacker with only a self-registered throwaway account can rebind their session to any customer ID and read that account's PII, orders, addresses, and stored payment tokens.
The affected software covers Adobe Commerce release lines 2.4.4 through 2.4.9 and Magento Open Source release lines 2.4.6 through 2.4.9, at the -2026-jul patch level and earlier. Exploitation attempts were observed in the wild shortly after Adobe published its advisory, with Sansec reporting that its WAF was already blocking attempts within hours of disclosure.
Why this matters for fingerprinting: the vulnerable range is 2.4.6 through 2.4.9-2026-jul. A scanner that returns "2.4" gives you nothing to work with. A scanner that returns Community 2.4.6 - 2.4.6-p7 (8 versions) tells you the store is almost certainly in scope, and that you should verify whether the August 2026 isolated patch has been applied before treating it as remediated. This is exactly the gap this tool is designed to close.
Patch note: the fix for APSB26-92 is distributed as an isolated patch file (24Xp-2026-08-001-CE), not as a new Composer package or git tag. Running composer update will not pull it. Merchants must apply the patch manually after ensuring they are on the latest -p release for their branch. This means version string detection alone cannot confirm a store is patched, but narrowing the version range is the first step in knowing which stores need the closest attention.
Nuclei's magento-version-detect template is a useful starting point, but its output often looks something like this:
[magento-version-detect:version] [http] [info] https://magento.test/ ["2.4"]
That single string "2.4" tells you the major branch but nothing useful for scoping risk. Is this 2.4.5? 2.4.9? Did they apply any of the 2.4.x-p patch releases? For a penetration test or attack surface assessment you need to know whether CVEs like CVE-2024-34102 (CosmicSting) or CVE-2022-24086 are in scope, and a major-branch string won't get you there.
This post covers two scripts I wrote to solve that: a fingerprint database builder (update_magento_fingerprints.py) and an async scanner (fingerprint_magento.py). Together they produce results like:
https://magento.test | Community 2.4.5 - 2.4.5-p9 (10 versions)
https://magento.test | Community 2.4.9
update_magento_fingerprints.py downloads every tagged Magento release from GitHub (both magento/magento2 for CE/EE and OpenMage/magento-lts for M1), then SHA-256 hashes every static file under the directories that are publicly web-accessible by default: lib/, js/, and skin/.
The result is a magento_fp_db.json that maps each file path to a per-hash record like:
"lib/web/mage/adminhtml/tools.js": {
"checksums": {
"a3f...": { "releases": ["CE 2.4.5", "CE 2.4.5-p1"], "first": "CE 2.4.5", "last": "CE 2.4.5-p1" },
"7bc...": { "releases": ["CE 2.4.5-p2"], "first": "CE 2.4.5-p2", "last": "CE 2.4.5-p2" }
},
"info_gain": 2.15
}
The info_gain score is computed from the Shannon entropy of how a file's hash is distributed across releases (how discriminating it is) weighted by how many releases it appears in. Files with high information gain are probed first during scanning.
Only meaningful static assets are hashed. Minified files, source maps, lock files, test fixtures, vendor directories, and build artefacts are explicitly excluded to avoid false matches from toolchain noise.
To update the database as new Magento releases ship:
# First run (all releases since 2.4.0)
python3 update_magento_fingerprints.py --token $GITHUB_TOKEN --since 2.4.0
# Add Magento 1 (OpenMage) as well
python3 update_magento_fingerprints.py --token $GITHUB_TOKEN --m1
# Preview without downloading
python3 update_magento_fingerprints.py --token $GITHUB_TOKEN --dry-run
A GitHub token is strongly recommended. Unauthenticated requests are capped at 60/hour and a full initial run downloads dozens of release zips.
A few design decisions worth calling out alongside the diagram:
Incremental by design. The skip step early in the pipeline is the reason you can run the updater weekly without re-downloading everything. It compares GitHub tags against meta.releases in the existing DB and only processes tags that are not already there.
Parallel downloads, serial merge. The ThreadPoolExecutor downloads multiple release zips concurrently (default 4 threads), but the merge_into_db step is called per-result after each future completes, so the DB state is never written from two threads at once.
info_gain is computed last. It is a full-DB recalculation rather than per-file, because the score depends on the total release count across all releases. A file that was unique to one release becomes less unique as more releases are added. Recomputing at the end means the probe ordering always reflects the current state of the whole database.
fingerprint_magento.py takes a target or list of targets and identifies the Magento version by fetching known static asset paths and comparing their SHA-256 (or MD5 for legacy data) hashes against the database.
For bulk target lists, a fast screening phase runs first. A MinimalProbeSet class computes the smallest set of high-coverage probe paths using a greedy set-cover algorithm, weighted by both version coverage and path accessibility (JS files, CSS files, and static paths score higher than paths that are often blocked). The top 4 of these are used as lightweight probes to confirm Magento is present before committing to the full fingerprint run.
Magento 2's static files are served from a versioned path like /static/version1234567890/frontend/.... The scanner fetches the homepage, parses the requirejs-config.js or baseUrl reference from the HTML, and adjusts probe URLs accordingly. The same homepage response is reused for the full fingerprint phase so no duplicate request is made.
Results are reported with a confidence tier:
| Result | Confidence |
| Single exact match (e.g. 2.4.5-p3) | High |
| 2-3 candidate versions | Medium |
| 4+ candidate versions or major-branch only | Low |
# Single target
python3 fingerprint_magento.py -u https://magento.test
# List of targets (one URL per line)
python3 fingerprint_magento.py -l targets.txt
# Filter to Magento 2 only, export CSV and NDJSON
python3 fingerprint_magento.py -l targets.txt -2 --export-csv out.csv --export-json out.ndjson
# Verbose: shows which probes matched
python3 fingerprint_magento.py -u https://magento.test -v
# Increase concurrency
python3 fingerprint_magento.py -l targets.txt --hosts 20
Scans are resumable. If interrupted with Ctrl+C, a state file is saved and the resume command is printed:
[->] To resume, run:
python3 fingerprint_magento.py --resume .scan_state_<timestamp>.json
Running against Magento hosts identified via Shodan (X-Magento-Vary header) gives results like:
| Host | Version Range | Confidence |
| 148.251.X.X:8080 | 2.4.6 - 2.4.6-p7 (8 versions) | Low |
| 149.102.X.X:80 | 2.4.8-p3, 2.4.8-p4, 2.4.8-p5 | Medium |
| 149.202.X.X:6081 | 2.4.6-p13 - 2.4.7-p10 (6 versions) | Low |
Where a range is returned (e.g. 2.4.6 - 2.4.6-p7) it means the hashes of the probed files were identical across all versions in that range. The file simply did not change between those patch releases, so the true version is somewhere inside the range.
Compare this to Nuclei's output for the same hosts, which would return "2.4" for all of them.
The following screenshots show both tools running against the same Magento instance, with the admin panel open alongside to confirm the actual installed version.
Both scripts are available on GitHub: http://peneuw2c-git01.fgxint.net:3000/klee/Magento-Fingerprinting