DEV Community

Cover image for What Your Laptop Tells Every Server: A 10-Minute Leak Audit with curl, dig and DevTools
Mak Atomic
Mak Atomic

Posted on

What Your Laptop Tells Every Server: A 10-Minute Leak Audit with curl, dig and DevTools

Open a terminal and run this:

curl -s https://www.cloudflare.com/cdn-cgi/trace
Enter fullscreen mode Exit fullscreen mode

You get a dozen lines back:

ip=203.0.113.7

loc=LV

colo=RIX

sni=plaintext
Enter fullscreen mode Exit fullscreen mode

ip= is your public address. loc= is the country Cloudflare maps it to. colo= is the data center that answered. sni=plaintext means the hostname you asked for travelled unencrypted in the TLS handshake.

That is one request to one server. Every site, API and package registry you touch gets the same data and more. Below is a small audit you can run in ten minutes: three tests, what each one shows, and a second run behind a VPN to see what changes and what does not.

TL;DR
  • our public IP, your DNS resolver and your WebRTC candidates are three separate exposure points. Fixing one does not fix the others.
  • A VPN changes who sees your IP and your DNS queries. It does not change cookies, logins or browser fingerprint.
  • Geolocation from an IP is a guess. Two services can disagree about the same address by a whole continent.

Test 1: What the server sees (public IP)

Start with the request above. Then ask a second service about the same address:

curl -s https://ifconfig.co/json | head -n 12
Enter fullscreen mode Exit fullscreen mode

When I ran both from the same machine, Cloudflare reported Latvia and the second service reported Tokyo. Same IP, same minute. IP geolocation databases are built from registry data, routing hints and guesses, and they lag behind when blocks of addresses move.

Two things follow from this:

"My location leaked through my IP" is usually true only at country or region level.
A service that blocks or allows you by country is working from a database that can be wrong. If a site ever blocked you while you sat in the "right" country, this is why.

Test 2: Who answers your DNS questions

Your browser knows the IP of a site because something resolved the name. That something is a DNS resolver, usually your router or your ISP, and it sees every hostname you look up, even when the page itself is HTTPS.

Check which resolver the world sees when you ask:

dig +short whoami.akamai.net
Enter fullscreen mode Exit fullscreen mode

The answer is the IP of the recursive resolver that reached Akamai's authoritative server on your behalf. If it belongs to your ISP, your ISP is reading your lookups. If it belongs to a public resolver you chose, that operator is.

Encrypted DNS closes the path between you and the resolver. DNS over HTTPS is defined in RFC 8484. It does not hide your lookups from the resolver itself, only from the network in between. The IETF's position on why this matters is blunt: RFC 7258 is titled "Pervasive Monitoring Is an Attack" and asks protocol designers to make mass surveillance harder.

Test 3: What the browser hands out via WebRTC

WebRTC lets two browsers connect directly. To do that, a browser gathers "ICE candidates", which are possible network addresses, and some of them come from a STUN server that reports your public address back. MDN documents the candidate types: host for local addresses, srflx for the address a STUN server saw.

Paste this into the DevTools console on any page:

const pc = new RTCPeerConnection({

  iceServers: [{ urls: "stun:stun.l.google.com:19302" }],

});

pc.createDataChannel("probe");

pc.onicecandidate = (e) => {

  if (e.candidate) console.log(e.candidate.candidate);

};

pc.createOffer().then((offer) => pc.setLocalDescription(offer));
Enter fullscreen mode Exit fullscreen mode

Look at the lines that contain typ srflx. The address in that line is the public IP the STUN server saw. Modern browsers hide local host addresses behind random .local names, but the srflx candidate is the one that matters here. If it differs from the IP in Test 1, something in your setup routes WebRTC outside your tunnel or proxy. That mismatch is the classic "WebRTC leak".

Run it again behind a VPN

Write down three results: public IP, resolver IP, srflx address. Connect to a VPN, then repeat all three tests.
Table: expected results of IP, DNS and WebRTC tests behind a VPN

If you want a visual version of the same data, the homepage of Atomic VPN has an "exposure" panel that lists the IP, city, ISP, device, browser and DNS a site can read from a single visit. I use it as a quick before-and-after check, but the three commands above are the real test because you can script them.

What a VPN does not change

Be clear about the limits, because "VPN" is sold as a stronger promise than it is.

  • Cookies and logins. If you are signed in, the site knows who you are regardless of IP.
  • Browser fingerprint. Fonts, canvas, screen size and extensions identify a browser without any IP at all.
  • What the VPN provider sees. You move trust from your ISP to the VPN operator. Read the logging policy and decide whether you accept it.
  • Plain HTTP pages. The tunnel protects the path to the VPN server, not the path from there to the site.

A small script to keep

Save it as leakcheck.sh and run it before and after you connect.

#!/usr/bin/env bash

echo "== public IP / country / colo =="

curl -s https://www.cloudflare.com/cdn-cgi/trace | grep -E '^(ip|loc|colo)='

echo "== resolver seen by Akamai =="

dig +short whoami.akamai.net

{% enddetails %}
Enter fullscreen mode Exit fullscreen mode

Diff the output of the two runs. If the IP changed but the resolver did not, you have found a leak in about two seconds.

Top comments (1)

Collapse
 
m_montazeri profile image
Mohammad Montazeri •

A caveat on the final two-second test: an unchanged recursive-resolver IP is not by itself proof that DNS escaped the tunnel. The same public resolver could be reached before and after connecting; its identity alone does not establish the path taken to it. I would describe that result as a prompt to check the intended DNS routing policy, rather than a confirmed leak. Also, dig does not verify the browser’s separate DoH path: Firefox documents its own resolver settings and fallback behavior. Keeping those two checks separate would help readers avoid a false diagnosis.

AI-assisted reply; I work on Lisar Connect.