← DevLog

3 min read

Anyone could create an account on the shop, and someone did

Nine customer accounts in one day, all from one IP address, none of them through the shop. Magento leaves account creation open on its REST API, and a headless front end never needs it.

The question was small. Nine new customer accounts had appeared on a B2B shop on the same day, all private individuals, none linked to a company. On that shop, nearly every real customer belongs to a company.

None of them had come through the shop.

What actually happened

All nine came from one IP address in Brazil, with a different browser signature on almost every request. They did not use the storefront at all. They called Magento's REST API directly:

POST /rest/default/V1/customers
POST /rest/V1/integration/customer/token
GET  /rest/V1/carts/mine
POST /rest/V1/carts/mine/items

Create an account, log in as it, open a cart, try to add something. 1,474 requests on the first day, a few dozen on the two days after, then nothing. No orders, no addresses, every cart empty. What they were after is guesswork. What matters is that they could get this far at all.

Why it was possible

Magento allows anonymous customer registration over REST out of the box. That makes sense for a classic Magento storefront. This shop has a separate front end, a PWA, and it never calls that endpoint. Nobody needed it open. It was open because that is the default, and nobody had ever asked.

Finding it took longer than it should

The web server kept about five days of logs, and this was eleven days back. The cart table had no IP address for these customers. What still had the answer was the CDN: its analytics go back further than the server's logs, and filtering on the exact seconds the accounts were created gave the IP address and every request it made.

Worth knowing before you need it: find out where your oldest request logs actually live. It is probably not the server.

The bug only the bot found

One more thing came out of it. Adding a product to the cart crashed with a 500 for a customer without a company. Real customers always have one, so nobody had ever hit it. It took a bot doing something no customer would do to show it. That is now a ticket of its own.

What we changed

  • The same day, an edge rule blocks anonymous POST requests to the customer endpoint on all four shop domains. Checking whether an email address is in use still works.

  • In Magento itself, the route will require admin rights, so the shop stays closed even without the edge rule in front.

Check yours in two minutes

Send an empty request to the endpoint:

curl -s -X POST https://www.example.com/rest/V1/customers \
  -H 'Content-Type: application/json' -d '{}'

An answer complaining about missing fields means the endpoint is open to anyone. A 401 or 403 means it is closed. Before you close it, check that your own front end and apps do not register customers through it. If they do not, there is no reason to leave it open.