Security Advisory Summary
- Release Date
- Affected Versions
- All J2Store versions prior to 4.1.8
- Fixed In
- J2Store 3.3.23, 4.0.23 and 4.1.8
- Overall 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
- Severity
- High CVSS 4.0 Base Score 7.1
- CVSS 4.0 Vector
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- 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- Type
- CWE-352 — Cross-Site Request Forgery
- 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}- Affected Component
components/com_j2store/controllers/{carts,checkouts,myprofile}.phpand the matching cart, checkout and myprofile templates (see file list below)
- Description
-
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, orderconfirm()) or the my-profile controller'ssaveAddress()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
- Severity
- High CVSS 4.0 Base Score 8.7 (draft)
- CVSS 4.0 Vector
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- 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- Type
- CWE-89 — SQL Injection
- Task
GET com_j2store / view={products,producttags} / task=browse—product_types[]filter parameter- Affected Component
administrator/components/com_j2store/models/{products,producttags}.php, reached viacomponents/com_j2store/controllers/{products,producttags}.php
- Description
-
The storefront product listing and product-tags listing both accept a
product_typesarray filter that F0F auto-populates straight from the request into model state. Both models built theproduct_type IN (...)SQL fragment by wrapping each supplied value in literal quotes andimplode()-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
- Severity
- High CVSS 4.0 Base Score 8.7 (draft)
- CVSS 4.0 Vector
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- 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- Type
- CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'); CWE-73 — External Control of File Name or Path
- Task
GET com_j2store / view=myprofile / task=download / token=<token> / pid=<productfile_id>- Affected Component
administrator/components/com_j2store/models/orderdownloads.php, reached viacomponents/com_j2store/controllers/myprofile.php
- Description
-
J2StoreModelOrderdownloads::getFilePath()built the on-disk path to a purchased digital download by concatenating the configured attachment folder with the product file's storedproduct_file_save_name, using onlyJPath::clean()(which normalises separators but does not resolve or reject..segments) and a plainJFile::exists()check — never confirming the resolved path stayed inside the configured attachment folder. If a product file'sproduct_file_save_nameever 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 downloadtoken/pidpair 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
- Severity
- High CVSS 4.0 Base Score 8.7
- CVSS 4.0 Vector
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- 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- Type
- CWE-840 — Business Logic Errors; CWE-345 — Insufficient Verification of Data Authenticity
- Task
POST com_j2store / view=callback / method=payment_paypal / paction=process- Affected Component
plugins/j2store/payment_paypal/paypalv32.php
- Description
-
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$errorsarray rather than stopping processing — and whenever any error was present,_processSale()unconditionally called$order->update_status(3)(Failed) on whateverorder_idthe request'scustomfield named, with no check on the order's current status. SincecheckStatusOfPaypal()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 toFAILED.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
FAILEDto 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
- Severity
- Medium CVSS 4.0 Base Score 5.1 (draft)
- CVSS 4.0 Vector
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- 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- Type
- CWE-330 — Use of Insufficiently Random Values
- Task
- N/A — not a single request; affects the
tokengenerated for every order at creation - Affected Component
administrator/components/com_j2store/tables/order.php(~1675,~3050)
- Description
-
The
tokenstored on each order — the bearer credential used for guest order lookup and digital-download authorization — was generated from the single site-wide Joomla secret fromconfiguration.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 theconfiguration.phpdisclosure 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
- Severity
- Medium CVSS 4.0 Base Score ~4.5
- CVSS 4.0 Vector
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- 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- Type
- CWE-116 — Improper Encoding or Escaping of Output
- Task
GET/POST(any method — reads$_REQUEST) directly toplugins/j2store/payment_paypal/payment_paypal/tmpl/notify.php- Affected Component
plugins/j2store/payment_paypal/payment_paypal/tmpl/notify.php
- Description
-
notify.phpis 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 thecom_j2storecheckout 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 intendedview=checkout&task=confirmPayment&orderpayment_type=...&paction=processset — 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 targetcom_j2storeURL 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
secretto 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=productsorview=producttagswhere aproduct_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
Failedwith 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
secrethas ever been exposed (e.g. via a backup, log, or config leak), rotate it inconfiguration.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.phpwhere a parameter value contains&,#, or a URL-encoded control character (%0d,%0a); notenotify.phpmust 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.