The case of the missing images

It is Friday evening, a bunch of campaign landing pages on Eloqua are about to be launched, and suddenly no images are being loaded. Instead, a “warning” is displayed. What happened? And what does it mean? Can it be solved?

Images are not visible, instead a system dialogue is presented

Prerequisites

Let’s take a look at the setup first. On client side, I’m using an iPhone 11 Pro with iOS17, pretty much stock, and Safari in Private mode. I live in a country where Private Relay is not available, so this is not enabled.

On the server side, the pages are hosted as landing pages in Eloqua. Eloqua is a marketing automation system by Oracle, and one of the key players in the martech industry.

When you are using Eloqua, there is an option to use your own (Sub)domain with Eloqua, which is basically achieved through CNAME DNS entries. These can be also used for assets such as images etc. So instead of the generic asset domain img06.en25.com the domain would be something like assets.myELQdomain.com. Other, similar solutions, have a similar option that works a similar way. It is safe to say that this is “industry standard”. This was also the setting of the landing page in question.

The issue

When loading the page, things got interesting. Using pages.myELQdomain.com/page would present the landing page, but every request to assets.myELQdomain.com would not be responded to. Changing the image URL to img06.en25.com however would immediately load the image, so it can’t be an issue of blocked content.

While trying to find an answer, I’ve tried different proxying methods to see the phone’s network traffic. The moment I used a proxy, the problem would not occur. “Sus”, as they say. The same problem happens when I reference the images on a website outside the Eloqua environment (or at least the myELQdomain.com). That makes it is really hard to investigate what’s happening here. But at least we know that the very interesting way of naming images – the generated file name has curly brackets – is not the culprit.

CNAME cloaking?

The first suspicion was a prevention of CNAME cloaking. CNAME cloaking means setting up a subdomain.mydomain.tld DNS entry which points to tracking.adtech.tld and is a common technique to keep 3rd party cookies alive. For everyone interested in a deeper read, here is a paper about CNAME cloakingor you read it in a simpler fashion in a blog post from NextDNS. Every tool that supports privacy (ad blockers, Pi-Hole, privacy conscious VPNs) have lists to prevent this, and basically either blocks the request from being sent, or resolve the domain subdomain.mydomain.tld to the server 0.0.0.0 or NXDOMAIN instead of the original entry, preventing 3rd parties from tracking you.

The suspicion for this being the reason arose as the assets domain is resolved to a CNAME which is resolved to another CNAME to another CNAME to the Akamai edge. That can however not be the (only) case, as for opening the image in a new tab would work. So it cannot be (only) that. What else can it be?

Multiple CNAMEs on top of each other

Private DNS?

The next suspicion was triggered by those 2 articles:
[https://help.nextdns.io/t/q6yq4xy/nextdns-stops-working-properly-when-updating-to-ios-17-ipados-17]
[https://news.ycombinator.com/item?id=36245362]

The private mode of iOS17 is using the Apple DNS server, thus enabling Private Relay through the back door. Interesting. And not possible to inspect (for me!), as this is based on QUIC and DNS over HTTPS. The moment you add a “man in the middle” (like a debugging proxy) everything  is resolved normally. It also does not happen on MacOS, even though Safari 17 for macOS should have the same measures as its iOS sibling.

But again, opening the image in a new tab works, so it can’t be that. Or not alone.

Another possible reason

Headers. The page is sending the request with a Sec-Fetch-Site: same-site header, whereas it is sending Sec-Fetch-Site: cross-site to the imgXX domains. This makes sense, and the behaviour would make sense if the seemingly same site is resolved to what is a cross-site request header.
As the headers show the same behaviour when trying to reproduce it in an external setting, the problem is not reproducible anymore.

A combination. None of the above alone seems to cause a problem. That makes it harder to detect, but also easier to circumvent.

How can I avoid it?

Host assets externally

Loading assets like images, CSS etc from an asset server does not seem to trigger the issue. So if you can, do that. It can be as easy as an AWS S3 bucket, or a bare metal nginx static web server. Your assets also may load faster, and you can fine tune the loading performance.

Host the pages externally

Let the landing page live outside Eloqua. You can still load the assets from Eloqua. This decreases the probability your page to run into a content blocker like uBlock Origin. On the other hand, it makes you miss out on the features of Eloqua like the block builder or easy form integration. You would need someone with deeper technical knowledge or a developer to help you here, especially transferring and connecting forms and actions. Delivering gated content is also changing.

Quick fix: change the URL

Open your landing page in the code view and replace every occurrence of assets.myELQdomain.com with img06.en25.com (or whatever the corresponding default for your Eloqua instance is). This might be cumbersome, but it is a quick solution.

What will the future bring?

The problem occurred on iOS17 in a private tab. It is said that approx. 20-35% of users use a sort of “incognito” or “private” mode to surf the web. However, the setting to use the same “non-tracking behaviour” in all web browser tabs, is very easy to reach, and activation is highly encouraged.  With the usually very fast adoption of new iOS version, it can be approximated that within the next 6 months 30% of all iOS traffic will see this behaviour. So ultimately, the root cause of this should be found out to see how it can be dealt with in a more sustainable manner.