Technical · 10 min read

DNS Poisoning Explained: How Indian ISPs Block Supabase

A technical deep dive into how Indian ISPs use DNS poisoning to block Supabase, what happens at each layer of the network stack, and why a reverse proxy is the only reliable fix that works for all your users.


How DNS resolution normally works

Before understanding DNS poisoning, you need to understand how DNS resolution works under normal conditions. DNS (Domain Name System) translates human-readable domain names like yourproject.supabase.co into IP addresses that computers use to route traffic.

Here is what happens step by step when your app makes a request to Supabase on an unblocked network:

Browser

Your app

1. Query

OS Resolver

Local cache

2. Forward

ISP Resolver

Recursive

3. Lookup

Auth NS

supabase.co

4. Returns real IP: 104.18.x.x (Supabase server)

Step 1: Your browser (or the Supabase client library) needs to connect to yourproject.supabase.co. It asks the operating system's DNS resolver for the IP address.

Step 2: The OS resolver checks its local cache. If the domain has not been looked up recently, it forwards the query to the configured DNS resolver, which is typically your ISP's recursive resolver.

Step 3: The ISP's recursive resolver queries the authoritative nameserver for supabase.co (managed by Supabase's DNS provider).

Step 4: The authoritative nameserver returns the real IP address of the Supabase server. Your browser connects to that IP, the TLS handshake completes, and the API request goes through.

This entire process takes milliseconds and is completely transparent to the user. Under normal conditions, it works flawlessly. But when an ISP is ordered to block a domain, this process is corrupted at Step 3.

How DNS poisoning works

DNS poisoning (also called DNS spoofing or DNS hijacking) is when a DNS resolver returns a fake IP address instead of the real one. In the case of Indian ISPs blocking Supabase, the ISP's recursive resolver is configured to intercept queries for *.supabase.co and return a sinkhole IP address.

Here is what the poisoned DNS resolution looks like:

Browser

Your app

Query

OS Resolver

Local cache

Forward

ISP Resolver

POISONED

BLOCKED

Auth NS

Never reached

Returns sinkhole IP: 49.44.79.236 (NOT Supabase)

Instead of forwarding the query to Supabase's authoritative nameserver, the ISP resolver intercepts it. It matches the domain against a blocklist, finds *.supabase.co on the list, and returns a sinkhole IP address like 49.44.79.236.

A sinkhole IP is a dead-end address. It might be an IP that simply drops all incoming connections, or it might be a server that returns a government-mandated block page. Either way, your app's request never reaches Supabase. The connection hangs until it times out, resulting in the ERR_CONNECTION_TIMED_OUT error.

What makes this effective

  • Wildcard matching: The ISP blocks all subdomains under *.supabase.co, not just a specific project. Every Supabase project URL is affected.
  • Silent failure: There is no error page or notification. The connection simply times out. Users and developers often waste hours debugging before realizing it is an ISP block.
  • Default path: Most devices use their ISP's DNS resolver by default. Users do not need to opt into the block; it is the default behavior on the network.

See it yourself: diagnostic commands

You can verify DNS poisoning on your network using these terminal commands. Compare the results from your ISP's DNS with a public DNS resolver like Cloudflare's 1.1.1.1 to see the difference. For a more detailed diagnostic guide, see our ISP block testing guide.

DNS lookup using your ISP's resolver (poisoned):

terminal
$ nslookup yourproject.supabase.co
Server: 198.18.0.1
Address: 198.18.0.1#53
Non-authoritative answer:
Name: yourproject.supabase.co
Address: 49.44.79.236 ← sinkhole IP (NOT Supabase)

DNS lookup using Cloudflare DNS (correct):

terminal
$ nslookup yourproject.supabase.co 1.1.1.1
Server: 1.1.1.1
Address: 1.1.1.1#53
Non-authoritative answer:
Name: yourproject.supabase.co
Address: 104.18.x.x ← real Supabase IP

Quick comparison using dig:

terminal
# Using ISP DNS (poisoned result)
$ dig +short yourproject.supabase.co
49.44.79.236
# Using Cloudflare DNS (correct result)
$ dig +short yourproject.supabase.co @1.1.1.1
104.18.x.x

Connection attempt showing the timeout:

terminal
$ curl -v --max-time 10 https://yourproject.supabase.co
* Trying 49.44.79.236:443...
* Connection timed out after 10001 milliseconds
* Closing connection
curl: (28) Connection timed out after 10001 milliseconds

The key diagnostic: If nslookup yourproject.supabase.co returns a different IP than nslookup yourproject.supabase.co 1.1.1.1, your ISP is poisoning the DNS response. The sinkhole IP will typically be in the 49.44.x.x range for Jio users.

Why .com works but .co does not

One of the most confusing aspects of the block for developers is that supabase.com works perfectly while supabase.co is completely blocked. This is not a bug in the blocking; it reflects Supabase's infrastructure architecture.

supabase.com (NOT blocked)

The marketing website and dashboard. This is where you log in, manage projects, and read documentation. It does not serve API traffic.

supabase.co (BLOCKED)

The API domain. Every project gets a subdomain like abcdefgh.supabase.co. All REST, Auth, Storage, and Realtime endpoints live here.

The blocking order targets *.supabase.co specifically. Since all API traffic uses the .co domain, the block effectively disables every Supabase-powered application for Indian users while leaving the dashboard accessible.

This is why you can still log into the Supabase dashboard, view your projects, and see that everything is running normally. The database is fine. The server is fine. The problem is that your users' browsers cannot reach the API endpoint because their ISP's DNS will not resolve the .co domain correctly.

Beyond DNS: Deep Packet Inspection (DPI)

DNS poisoning is the primary blocking mechanism, but some Indian ISPs employ an additional layer of blocking called Deep Packet Inspection (DPI). This is important to understand because it explains why simply changing your DNS resolver to 1.1.1.1 or 8.8.8.8 does not always fix the problem.

When your browser establishes a TLS (HTTPS) connection, the first step is the TLS handshake. During this handshake, your browser sends a field called the Server Name Indication (SNI) in plaintext. The SNI tells the server which domain the client wants to connect to, and it is visible to anyone inspecting the traffic, including your ISP.

Here is what happens with DPI-based blocking:

Step 1: You switch your DNS to Cloudflare's 1.1.1.1. DNS now resolves correctly and returns Supabase's real IP address.

Step 2: Your browser starts a TLS handshake with Supabase's real IP. In the Client Hello message, the SNI field says yourproject.supabase.co.

Step 3: The ISP's DPI equipment inspects the SNI field, sees supabase.co, and drops or resets the connection before TLS can complete.

Result: Even though DNS resolved correctly, the connection still fails. You get the same ERR_CONNECTION_TIMED_OUT or ERR_CONNECTION_RESET error.

Why this matters

DPI-based blocking means that even if you bypass DNS poisoning by using a different resolver, the ISP can still see and block the connection based on the hostname in the TLS handshake. This is why DNS changes are not a reliable fix, even for local development. The only way to fully bypass both DNS poisoning and DPI is to ensure the domain supabase.co never appears in any part of the connection that the ISP can inspect.

Why just changing your DNS does not fix it for your users

Even if changing DNS to 1.1.1.1 bypasses both DNS poisoning and DPI on your machine (which is not guaranteed), it only fixes the problem for you. Your production users are still affected.

The scale of the problem

  • 500M+ Jio subscribers all use Jio's default DNS resolver. They have not changed it. They will not change it. Most of them do not know what DNS is.
  • Mobile users cannot easily change DNS. On Android without root, changing DNS requires a third-party app or a Private DNS setting that most users will never configure. On iOS, per-network DNS settings reset frequently.
  • You cannot ship a DNS change. Your app's code has no control over which DNS resolver the user's device uses. You cannot programmatically change their DNS settings.
  • ISPs intercept public DNS too. Some ISPs redirect DNS queries to known public resolvers (like 8.8.8.8) back through their own resolver, negating the workaround entirely.

The fix must be transparent to end users. They should not need to install anything, change any setting, or even know that a block exists. The solution needs to work at the infrastructure level, not the client level.

How a reverse proxy bypasses the block

A reverse proxy solves both DNS poisoning and DPI in one step. Instead of your app connecting directly to yourproject.supabase.co, it connects to a domain you control (or one provided by JioBase) that is not on the ISP's blocklist.

Here is the complete flow with a reverse proxy:

User's device (client-side, ISP can inspect)

Your App

Browser / Client

HTTPS SNI: yourapp.jiobase.com

JioBase Proxy

Cloudflare Edge

HTTPS Server-side

Supabase

*.supabase.co

Server-side (ISP cannot inspect)

DNS query: The browser resolves yourapp.jiobase.com, not supabase.co. The ISP's DNS has no block for this domain, so it returns the real Cloudflare IP.

TLS handshake: The SNI field says yourapp.jiobase.com, not supabase.co. DPI equipment sees nothing to block.

Proxy forwarding: The Cloudflare Worker receives the request and forwards it to yourproject.supabase.co on the server side. This server-to-server connection happens on Cloudflare's network, completely outside the ISP's control.

Response: Supabase responds to the Worker, which forwards the response back to the user's browser. The entire round trip adds only 1-5ms of latency.

The ISP never sees supabase.co in any DNS query, SNI field, or HTTP header. From the ISP's perspective, the user is simply accessing a Cloudflare-hosted domain. There is nothing to block.

Verifying the fix

After setting up your proxy through JioBase or a self-hosted Cloudflare Worker, you can verify it works by running these commands from an affected ISP connection:

Verify DNS resolves correctly for the proxy domain:

terminal
# Proxy domain resolves normally (not blocked)
$ nslookup yourapp.jiobase.com
Name: yourapp.jiobase.com
Address: 104.21.x.x ← Cloudflare IP (correct)

Verify API requests work through the proxy:

terminal
# Test REST API through the proxy
$ curl -s https://yourapp.jiobase.com/rest/v1/ \
-H "apikey: your-anon-key" \
-H "Authorization: Bearer your-anon-key"
{"message":"ok"} ← success, proxy is working

Compare direct vs proxy connection:

terminal
# Direct connection (blocked, times out)
$ curl --max-time 5 https://yourproject.supabase.co/rest/v1/
curl: (28) Connection timed out
# Through proxy (works instantly)
$ curl --max-time 5 https://yourapp.jiobase.com/rest/v1/
HTTP/2 200 OK

Test from the right network. Make sure you are testing from a Jio, Airtel, or ACT Fibernet connection. If you are on a VPN or using a different ISP, the direct connection might work too, which does not prove the proxy is solving the block. Disable your VPN and test on mobile data for the most accurate result.

Frequently Asked Questions

Can DNS poisoning be detected programmatically from my app?
Not reliably from client-side JavaScript. Browsers do not expose DNS resolution details to web pages. You can detect connectivity failures (timeouts, connection resets) but cannot determine the cause. From a server or terminal, you can compare DNS results from different resolvers using nslookup or dig as shown above.
Does Encrypted Client Hello (ECH) protect against SNI-based blocking?
ECH (formerly ESNI) encrypts the SNI field during the TLS handshake, which would prevent ISPs from inspecting the hostname. However, ECH is not widely deployed yet, and ISPs can block ECH-enabled connections entirely as a fallback. It is also a client-side feature that requires browser support and server support, neither of which you can control for your end users. A reverse proxy remains the more practical solution.
Does a reverse proxy add latency to API requests?
A small amount, typically 1-5ms. JioBase runs on Cloudflare's edge network with 300+ data centers worldwide, including multiple locations in India. The Worker processes the request at the nearest edge location to the user, then forwards it to Supabase's servers. The added latency is negligible compared to the alternative of the request not working at all.
Can the ISP block the proxy domain too?
In theory, any domain can be blocked. However, blocking a custom proxy domain is far less likely because it is not on any existing blocklist. If you use your own custom domain with JioBase, the domain is unique to your application. ISP blocklists target known services by their well-known domains, not individual application domains. Additionally, if a proxy domain were ever blocked, you could switch to a new domain in minutes.

Bypass DNS poisoning in under 60 seconds

Deploy your own Supabase reverse proxy and make your app work for every user in India. No DNS changes, no VPN, no client-side workarounds. One command.

npx create-jiobase — self-host on Cloudflare Workers for free

Self-host runs on Cloudflare Workers free tier (100k requests/day). No credit card required.

Sunith VS

Written and verified by

Sunith VS

Building tools that help Indian developers ship without ISP interference. Creator of JioBase.