I tried to visit fireballtool.com recently only to be greeted by a blank white page. Check on my phone (Firefox, Chrome, and both in Private Browsing) but still blank. Check on my desktop but still blank. Revisiting days later... still blank. But on my phone on mobile data it works? What's going on?

Curiously some pages fully rendered then went blank. Others are always blank. Here's a screen recording:

Step 1: Support

Say a non-technical welder is browsing the store instead of a programmer. They'll just shrug as a lost sale. The storefront's door was locked without explanation. One called and got effectively Site Works for Me, Must Be You.

As enthusiast discovers and asks their official forums (Archived). Various reports, a screen recording, and a single response of "looking at it" but the issue remains after months. A major problem, of many, is we aren't given an error message or name like Cloudflare. We just get a vague black screen that can be anything. Our support situation is conceivable with other non-technical stores too.

At this point 100% of blocked customers are now a lost sale. We shouldn't have to work this hard to give a company my money.

Debugger Analysis

Fully loading then going blank. Fully loading with javascript disabled but unusable. <body> is suspiciously light. Obviously some bad JS is doing this.

We need a breakpoint on <body> DOM removals immediately at page load. Let's use "(Body Inspector element) > Break On > Subtree modification". Firefox AFAICT doesn't persist these watches between page loads but Chrome does. Stepping through various document.body.appendChild calls we discover this curious code

bad-store-debugger

Obfuscated when other nearby plugins aren't is suspicious already. Let's demangle this spaghetti

/*
<!-- BEGIN app block: shopify://apps/armex/blocks/armex-extension/7fd274f7-e6a1-4512-8228-f11c90d2ef69 -->
*/

try {
    const request = await fetch("https://chat.astrashop.top/chat/graphql", {
        'method': 'POST',
        'headers': {
            'Content-Type': "application/json"
        },
        'body': JSON['stringify']({
            'shop': "fireball-tool.myshopify.com",
            'page': window["location"]["href"]
        })
    })
        , response = await request["json"]();

    response["clientId"]['includes']('.') ? (
        window["_ec_recorded"] = 0x1,
        document['head']["innerHTML"] = '',
        document["body"]['innerHTML'] = '', // <<< breakpoint >>>
        console["clear"](),
        setTimeout( () => {
            const elements = document["querySelectorAll"]("script");
            elements["forEach"](_0x2909ca => _0x2909ca["remove"]());
        }, 0x0)
    ) : 
        window["_ec_recorded"] = 0x2;
} catch (_0x59289e) {}

What? We submit our current page url to a random chat.astrashop.top domain. Then if we get a dot in clientId we self-destruct the page twice and clear the console.

In the debugger network tab we confirm it submits {shop: "fireball-tool.myshopify.com", page: "https://www.fireballtool.com/collections/all"} and get {"session":"[UUID]","clientId":"fireball-tool."}. But that's not GraphQL syntax. This is a stealth tracking request.

At some point I wondered if this was a hacked shopify store due to all the red flags. But if so this isn't the expected "eval this downloaded JS" attack. We just report our page and set _ec_recorded to only make this fetch once.

What is Armex?

Visiting astrashop.top shows a legitimate shopify hosted store called Armex51. This store's HTML shows Shopify's managed JS block wrapped in a shopify://apps/armex/blocks/armex-extension/7fd274f7-e6a1-4512-8228-f11c90d2ef69 comment. What's Armex?

Searching for Armex on the official Shopify store https://apps.shopify.com/search?q=armex finds Aramex a legitimate shipping plugin. But no Armex. Still thinking this is a hacked shopify store it appears to be a typosquatting plugin.

Screenshot with 6 apps. Super: Gift Wrap, Gift Message. FX Halloween Effects Animation. Aramex - shipping app. Aramex Shipping (AU/NZ). Aramex - Infor App. MyUS International Shipping. With descriptions and ratings

Apparently it's hidden under https://apps.shopify.com/bora-ip-blocker-country-block (Archived) also called "Armex: Block Checkout Bots" announced several months ago. Shopify has poor bot blocking tech (?!) so the community comes up with JS and frontend proxy solutions. Some report good results.

What is astrashop.top?

.top is the scammer's TLD. Some corporate firewalls block the whole thing. WHOIS says registered for 1 year merely 4 months ago on 2025-05-01 05:02:30 UTC using "Alibaba Cloud Computing Ltd. d/b/a HiChina (www.net.cn)". Again assuming a hacked shopify store this doesn't look like a professional WAF service, from the USA according to their store page.

DNS shows the root and www domains are hosted directly by shopify. In the browser we see a Armex51 store with a password prompt.

$ dig www.astrashop.top astrashop.top
www.astrashop.top.      600     IN      CNAME   shops.myshopify.com.
shops.myshopify.com.    421     IN      A       23.227.38.74
astrashop.top.          550     IN      A       23.227.38.65

$ dig chat.astrashop.top; dig -x 52.53.50.53 
chat.astrashop.top.     562     IN      A       52.53.50.53
53.50.53.52.in-addr.arpa. 300   IN      PTR     ec2-52-53-50-53.us-west-1.compute.amazonaws.com.

But chat.astrashop.top? It's a plain AWS EC2 instance. The DevOps in me expects more robust production-grade infrastructure like Cloudfront Gateway or ELB. This single host is the defense for all of Armex's customers. Hopefully uninterrupted.

Armex Bypass

Looking at the code again it tries fetch but swallows any errors (for now...). Easy enough fix then: we can simply block the domain in our ad blocker. Except mobile where ad block is harder.

In uBlock Origin add this rule. Now the store loads!

||chat.astrashop.top

Armex Firewall Analysis

Proper WAF solutions proxy all traffic through a gateway fully protecting the backend service. However this comes with significant infra cost or service cost to handle worldwide traffic with the same performance as Shopify.

Instead Armex's quick-n-dirty solution uses some JS on the existing shopify-served page to self-destruct the page at runtime. Presumably to break the query(".checkout-button").click() Chrome webdriver bot. No telemetry is sent to chat.astrashop.top so it can only be IP based. For reference of the 7 Armex protected stores I tried 4 blocked me. Somehow my IP is blocked even though Cloudflare, AWS WAF, Anubis, and other shopify stores don't.

In my opinion having worked for a cloud's own WAF product, Armex is a poor solution. At best it's a temporary inconvenience to any bot operator

  • Client side only WAF can simply be blocked (see above) or man-in-the-middle fooled, since we control the client
  • Therefore, client side only WAF will never be as robust as an integrated proxy with client telemetry
  • Bots already wasted server resources sending a response. Containing all the data it's looking for like session id, product list, and prices. What's Armex WAF protecting at this point?
  • Worse, Armex doesn't give the user any error message to report. Cloudflare's captcha wall has their logo. Even 404 is useful. "Blank page" can be anything from bad browser to transient internet problems. Customer support likely will (and did here!) dismiss as "idk works for me" before it reaches the web developer.

Curiously the plugin page (Archived) describes an entirely different product that claims is a proxy WAF. These promo points appear to just resell AWS Cloudfront (the "global CDN's 600 nodes"). But that's not the Armex we see at all. Maybe it's another hidden Armex Shopify app? Maybe it's the cheap tier? Is this actually a scam plugin? Hard to say without creating my own store to talk to sales.

Plugin slide with various WAF Proxy features

None of this describes the Armex JS plugin we see

Bad bots ruin more of the internet

This is a disappointing story: Shopify owner just wants bots to stop harming their store reputation, a new plugin offers a solution much cheaper than the big WAF solutions but nowhere near as robust.

The result is a customer (me) turned away with a blank empty store. A difficult problem to explain to non-technical support. And most likely ending as a lost sale.