Skip to content
Nivocart Issues 26

Nivocart Issues 26

github.com • October 16, 2026

The download() method in catalog/controller/account/order.php has no authentication gate, unlike every other order action ( index() , picklist() , info() ). It passes the raw order_id GET parameter directly to the model, which filters by WHERE order_id=(int)X AND customer_id=(int)$this->customer->getId() . For unauthenticated callers, getId() returns 0 (hardcoded in system/library/customer.php:300–302 ), which is identical to the customer_id value stored for guest checkouts. Because guest orders are legitimately stored with customer_id=0 , the model filter matches any guest order with no account, no session, no credentials required. Enumeration is trivial due to order IDs being sequential integers.

Any unauthenticated attacker can iterate order_id values and retrieve the full invoice for every guest order ever placed, which includes the customer's full name, billing and shipping addresses, phone number, email address, product line items, and order totals. This constitutes unauthenticated disclosure of personal data for all guests who have ever checked out.

The download() method in catalog/controller/account/order.php has no authentication gate:

As compared to index() , picklist() , info() which all open with:

On a local test instance, insert test victim guest order.

Confirm the MySQL database has been populated correctly.

Download the invoice without any login or cookies.

Similarly opening the link directly in a web browser proves it.

Perform a control test against gated endpoint to prove requirement for authentication.

Viewing the gated endpoint link in the web browser redirects us to the login page.

Add the same gate used by info() and picklist() at the top of download() :