Release date: 2026-09-14
Affected versions: All J2Store versions prior to 4.1.8
Fixed in: J2Store 3.3.23, 4.0.23 and 4.1.3
Severity: High (CVSS 4.0 scores range from 4.5 to 8.7)

Overview

J2Store 3.3.23, 4.0.23 and 4.1.8 are security releases that address six vulnerabilities in the com_j2store component: incomplete CSRF protection that left the checkout and my-profile controllers (and, for the admin side, product-file management) able to be driven by a forged cross-site request; an unauthenticated blind SQL injection in the storefront product and product-tags listing filters; a path-traversal issue in the customer-facing file-download handler that could expose arbitrary files readable by the web server; a logic flaw in the PayPal callback handler that let an unauthenticated request mark any order as FAILED, regardless of the order's real payment status or current state; an order access token derived from a keyed hash of the site secret and a guessable order ID rather than random generation, which becomes forgeable for any order once that secret is known by any means; and unescaped request data reflected into the redirect the PayPal notify handler issues, allowing query-parameter injection into the follow-up checkout request.

All six issues affect every currently supported release line: Joomla 3 (J2Store 3.3.x), Joomla 4.0 (J2Store 4.0.x), and Joomla 4.1 (J2Store 4.1.x).

Users running J2Store 3.3.22 or earlier, 4.0.22 or earlier, or 4.1.7 or earlier are advised to update immediately: to 3.3.23 if you are still on Joomla 3, to 4.0.23 if you run 4.0.x, or to 4.1.8 if you run 4.1.x.

Vulnerabilities Fixed

1. Missing CSRF protection on cart, checkout and myprofile controllers

CVE: CVE-2026-78081
Task: com_j2store / view={carts,checkouts,myprofile} / task={addItem,forceshipping,update,clearCart,remove,setcurrency,applyCoupon,removeCoupon,applyVoucher,removeVoucher,estimate,shippingUpdate,addtowishlist,login_validate,register_validate,guest_validate,guest_shipping_validate,billing_address_validate,shipping_address_validate,shipping_payment_method_validate,confirm,saveAddress}
CVSS:4.0 AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N / Base Score: 7.1 / Severity: High
CVSS:3.1 AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N / Base Score: 6.5 / Severity: Medium
CWE: CWE-352 — Cross-Site Request Forgery
Files: components/com_j2store/controllers/{carts,checkouts,myprofile}.php and the matching cart, checkout and myprofile templates (see file list below)

A previous release added JSession::checkToken() to the cart controller's state-changing actions. This release completes that hardening across the rest of the storefront: none of the checkout controller's flow-advancing actions (guest/registered login and registration during checkout, billing and shipping address submission, shipping/payment method selection, order confirm()) or the my-profile controller's saveAddress() validated an anti-CSRF token, and the matching templates generated their forms with no token attached. As with the earlier cart-only finding, the token check is opt-in per controller action, so every affected task was reachable by a forged cross-site request as long as the victim's browser held a valid session for the store.

Impact: A forged request riding a victim's active checkout session could silently overwrite the billing or shipping address before order confirmation — the most consequential sub-case, since it opens the door to redirecting a paid order's goods to an attacker-controlled address — or tamper with a saved profile address via saveAddress(). As before, each forged request executes with only the victim's own session privileges, so there is no cross-account data access.

2. Blind SQL injection in the storefront product list

CVE: CVE-2026-81567
Task: GET com_j2store / view={products,producttags} / task=browseproduct_types[] filter parameter
CVSS:4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N / Base Score: 8.7 (draft) / Severity: High
CVSS:3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N / Base Score: 7.5 / Severity: High
CWE: CWE-89 — SQL Injection
Files: administrator/components/com_j2store/models/{products,producttags}.php, reached via components/com_j2store/controllers/{products,producttags}.php

The storefront product listing and product-tags listing both accept a product_types array filter that F0F auto-populates straight from the request into model state. Both models built the product_type IN (...) SQL fragment by wrapping each supplied value in literal quotes and implode()-ing them together, with no escaping and no check that the values were even valid product-type keys. A value containing a ' closed the string early, letting an unauthenticated visitor append arbitrary SQL — e.g. a boolean- or time-based condition — to extract data from the database blind, with no authentication and no user interaction beyond the crafted request.

Impact: Unauthenticated, blind extraction of arbitrary database content (e.g. customer records, order data, stored credentials/tokens) via boolean- or time-based inference, reachable on any public storefront that exposes the standard product listing or product-tags filter.

3. Arbitrary file read via task=download

CVE: CVE-2026-81568
Task: GET com_j2store / view=myprofile / task=download / token=<token> / pid=<productfile_id>
CVSS:4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N / Base Score: 8.7 (draft) / Severity: High
CVSS:3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N / Base Score: 7.5 / Severity: High
CWE: CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'); CWE-73 — External Control of File Name or Path
Files: administrator/components/com_j2store/models/orderdownloads.php, reached via components/com_j2store/controllers/myprofile.php

J2StoreModelOrderdownloads::getFilePath() built the on-disk path to a purchased digital download by concatenating the configured attachment folder with the product file's stored product_file_save_name, using only JPath::clean() (which normalises separators but does not resolve or reject .. segments) and a plain JFile::exists() check — never confirming the resolved path stayed inside the configured attachment folder. If a product file's product_file_save_name ever contained a ../ traversal segment — most plausibly via the CSRF-forgeable admin product-file save actions described in Issue 1, but equally by any future integration or bug that writes that field — any customer holding a valid download token/pid pair for that product file could have the traversal resolve to a path outside the attachment folder and download any file readable by the web server (e.g. configuration.php).

Impact: Unauthenticated-adjacent (token-gated) arbitrary file read, including files containing database credentials and other secrets, chainable with Issue 1's admin CSRF gap to poison a target file entry without ever compromising an admin account directly.

4. Any order can be marked Failed by anyone

CVE: CVE-2026-82189
Task: POST com_j2store / view=callback / method=payment_paypal / paction=process
CVSS:4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N / Base Score: 8.7 / Severity: High
CVSS:3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N / Base Score: 7.5 / Severity: High
CWE: CWE-840 — Business Logic Errors; CWE-345 — Insufficient Verification of Data Authenticity
File: plugins/j2store/payment_paypal/paypalv32.php

A previous release stopped the PayPal IPN listener from letting an unverified callback confirm an order for free, but a failed IPN signature check was still passed down into _processSale() as an ordinary entry in its $errors array rather than stopping processing — and whenever any error was present, _processSale() unconditionally called $order->update_status(3) (Failed) on whatever order_id the request's custom field named, with no check on the order's current status. Since checkStatusOfPaypal() trivially returns false for any POST that isn't a real PayPal transaction, an anonymous attacker only needed to guess or enumerate a numeric order id and POST a forged IPN body to flip that order — pending, already confirmed, already shipped, any of them — straight to FAILED.

Impact: Unauthenticated denial-of-service against the order pipeline: mass-failing pending orders to disrupt revenue and force manual reprocessing, or flipping already-fulfilled orders back to FAILED to cause operational confusion (unwarranted refunds/cancellations, customer-support load). Unlike the earlier confirmation-fraud issue, this required no correct payment amount or transaction data at all.

5. Predictable/forgeable order access token

CVE: CVE-2026-82190
Task: N/A — not a single request; affects the token generated for every order at creation
CVSS:4.0 AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N / Base Score: 5.1 (draft) / Severity: Medium
CVSS:3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N / Base Score: 5.9 / Severity: Medium
CWE: CWE-330 — Use of Insufficiently Random Values
Files: administrator/components/com_j2store/tables/order.php (~1675, ~3050)

The token stored on each order — the bearer credential used for guest order lookup and digital-download authorization — was generated from the single site-wide Joomla secret from configuration.php (the same value Joomla reuses for its anti-CSRF form tokens). The token is generated once at order creation and is never regenerated afterward.

Impact: Anyone who obtains the site's Joomla secret — for example via the configuration.php disclosure in Issue 3 above, or any other config-leak vector on the site — can compute a valid access token for any order on the site without ever having placed one, gaining guest access to that order's details and any purchased digital downloads. Because the token is never rotated, this exposure persists indefinitely even after the underlying secret-disclosure vector is patched, unless the Joomla secret itself is also rotated. The attack complexity (AC:H) is high because it depends on the secret already being known through a separate vector; it is not directly exploitable by an anonymous visitor with no other foothold.

6. Unescaped request data reflected into PayPal notify redirect

CVE: CVE-2026-82191
Task: GET/POST (any method — reads $_REQUEST) directly to plugins/j2store/payment_paypal/payment_paypal/tmpl/notify.php
CVSS:4.0 AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N / Base Score: ~4.5 / Severity: Medium
CVSS:3.1 AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N / Base Score: 4.3 / Severity: Medium
CWE: CWE-116 — Improper Encoding or Escaping of Output
File: plugins/j2store/payment_paypal/payment_paypal/tmpl/notify.php

notify.php is a standalone PayPal IPN entry point that bypasses Joomla's normal component dispatch, so it is reachable by anyone, not only PayPal's servers. It took every key/value pair from $_REQUEST (GET, POST, and COOKIE) and concatenated them directly into the query string of a redirect it issues to the com_j2store checkout controller, with no encoding at all.

Because the values are not confined to their intended query-string position, a &, =, or # in an attacker-supplied field is interpreted as new query syntax rather than literal data.

Impact: A crafted link to this endpoint, if followed by a victim's browser (or an automated system that fetches it), causes the resulting redirect to com_j2store's checkout controller to carry attacker-chosen query parameters instead of only the intended view=checkout&task=confirmPayment&orderpayment_type=...&paction=process set — parameter injection/smuggling into that follow-up request. This requires a victim to load the crafted link; it does not by itself grant an unauthenticated attacker anything they could not already obtain by requesting the target com_j2store URL directly with their own parameters.

Who Is Affected

Any J2Store installation on 3.3.22 or earlier, 4.0.22 or earlier, or 4.1.7 or earlier, where:

  • The storefront checkout or profile pages are used (issue 1 requires only a normal browsing/checkout session, guest or authenticated)
  • The storefront product listing or product-tags filter UI is publicly accessible (issue 2 requires no authentication)
  • Digital/downloadable products are sold (issue 3 requires a valid download token, obtainable via any legitimate purchase of a downloadable product)
  • PayPal is enabled as a payment method (issue 4 requires no authentication; issue 6 additionally requires a victim, or an automated system, to follow a crafted link to notify.php)
  • Any orders exist at all (issue 5 requires the site's Joomla secret to already be known through some other means, e.g. issue 3 above)

Known Compatibility Impact

Any custom template override, or third-party add-on that ships its own copies of the cart, checkout, or myprofile templates (this includes some checkout add-ons, notably Easy Checkout), will need the same anti-CSRF token added to its own forms. Until updated, those templates will produce an "Invalid Token" error on affected actions after this update is installed.

Actions Required

Backup your site. Update to J2Store 3.3.23 if you are still on Joomla 3, 4.0.23 if you run 4.0.x, or 4.1.8 if you run 4.1.x, as soon as the relevant release is available. No configuration changes are required beyond installing the update and, if applicable, updating any custom or third-party checkout/myprofile templates per the compatibility note above.

If you are unable to update immediately:

  • Issue 1: If your hosting provider offers a Web Application Firewall (WAF), ask about enabling generic CSRF protections for your storefront.
  • Issue 2: If a WAF is available, block requests to view=products or view=producttags where a product_types[] value contains a ' character.
  • Issue 3: Monitor for unexpected download requests, and confirm no product file's stored save-path contains ...
  • Issue 4: Monitor for orders transitioning to Failed with no matching PayPal transaction in your PayPal account, and disable PayPal if that isn't practical to monitor.
  • Issue 5: If you have any reason to believe your Joomla secret has ever been exposed (e.g. via a backup, log, or config leak), rotate it in configuration.php — this invalidates every existing order token site-wide, so guest order-lookup and download links issued before the rotation will stop working and customers will need to re-request access.
  • Issue 6: If a WAF is available, block requests to notify.php where a parameter value contains &, #, or a URL-encoded control character (%0d, %0a); note notify.php must remain reachable by PayPal's servers, so it cannot simply be blocked outright.

Credits

Phil Taylor (mySites.guru): discovery and responsible disclosure of all six issues.

Thank you to the Joomla Security Strike Team for their help in the matter.

Stay Updated

Subscribe for free and be the first to know about the latest features, updates, and new additions.