Keep secrets out of web addresses—even when the connection is encrypted
Understand which URL components TLS protects on the wire, what DNS, SNI, IP metadata, browsers and logs still reveal, and redesign secret-bearing links safely.
A password-reset link uses HTTPS, so its path and query are encrypted between the browser and the TLS endpoint. That does not make the token private everywhere it travels. It can still enter browser history, proxy and application logs, analytics systems, screenshots, support tickets and referrer flows. TLS protects a connection segment; it is not a data-handling policy.
Split the URL into components
https://accounts.example.net:443/reset/confirm
?token=abc123&campaign=mail
#step-two
| Component | Example | Sent in HTTP request? |
|---|---|---|
| Scheme | https | Determines connection behavior |
| Host | accounts.example.net | Used for DNS, TLS name and HTTP authority |
| Port | 443 | Visible transport destination |
| Path | /reset/confirm | Inside encrypted HTTP data |
| Query | token=... | Inside encrypted HTTP data |
| Fragment | #step-two | Not sent in the HTTP request; available to the browser page |
See where TLS starts protecting bytes
Client
├─ DNS lookup for accounts.example.net
├─ TCP/QUIC connection to server IP:port
├─ TLS handshake (SNI may expose hostname without ECH)
└─ encrypted HTTP request
GET /reset/confirm?token=abc123 HTTP/1.1
Host: accounts.example.net
After the TLS handshake establishes keys, the HTTP method, path, query, headers and body are encrypted on that connection. A passive observer does not read the path or query from ordinary HTTPS traffic. The TLS terminator—CDN, reverse proxy, load balancer or origin—decrypts them and can log or forward them.
Account for DNS and destination metadata
Before connecting, the client usually resolves the hostname. Plain DNS exposes that query to the local network and resolver. Encrypted DNS protects the hop to the resolver, not necessarily the resolver’s knowledge or later authoritative lookup. The destination IP and port remain visible to network routing, and traffic size and timing can support inference.
dig accounts.example.net A
dig accounts.example.net HTTPS
openssl s_client -connect accounts.example.net:443 -servername accounts.example.net </dev/null
These diagnostics reveal operational metadata; do not paste unredacted output into public tickets when hostnames are sensitive.
Understand SNI and Encrypted Client Hello
Most shared TLS hosting needs a server name in ClientHello. Traditional SNI is plaintext and can reveal the hostname. RFC 9849, published in 2026, standardizes Encrypted Client Hello (ECH), which encrypts the inner ClientHello and protects SNI when the client, DNS discovery and service all support it and ECH is accepted.
ECH is not a reason to assume hostname privacy. Deployment, fallback, resolver visibility, shared-server anonymity sets and traffic analysis all matter. Verify the actual browser/network path rather than checking a certificate setting alone.
Remember that certificate names can be public
TLS 1.3 encrypts the server certificate after ServerHello, but publicly trusted certificate issuance is commonly recorded in Certificate Transparency logs. Domain and subdomain names in certificates can therefore be discoverable independently of a connection. Avoid placing confidential customer identifiers in DNS names.
Find every place a query secret can leak
- Browser history, bookmarks, address-bar synchronization and autocomplete.
- Reverse-proxy, CDN, WAF, application and access logs.
- Monitoring transaction names and distributed traces.
- Analytics beacons and error-reporting SDKs.
- Copied links, screenshots, chat previews and support tickets.
- Referrer information on subsequent navigation, depending on policy.
- Backups, data lakes and security-event pipelines fed by logs.
GET /reset/confirm?token=abc123 HTTP/2
Referer: https://mail.example.test/inbox
The current default browser referrer policy often reduces cross-origin detail, but applications must set an explicit policy and must not depend on browser defaults to protect credentials.
Use a strict referrer policy on sensitive flows
Referrer-Policy: no-referrer
Cache-Control: no-store
Content-Security-Policy: default-src 'self'; frame-ancestors 'none'
no-referrer prevents the page from sending referrer data on outgoing navigation. no-store instructs caches not to store the response. Neither removes an existing URL from local history or server logs, so the token itself still needs short lifetime and single-use enforcement.
Exchange a one-time URL token immediately
GET /reset/confirm?t=opaque-one-time-handle HTTP/1.1
HTTP/1.1 303 See Other
Location: /reset/new-password
Set-Cookie: reset_session=opaque_session; Secure; HttpOnly; SameSite=Strict
Cache-Control: no-store
Referrer-Policy: no-referrer
Validate and consume the URL token server-side, establish a narrowly scoped short-lived session, then redirect to a clean URL. Bind it to the intended account and action, store only a keyed hash where practical, rate-limit attempts and invalidate it after successful use.
Do not move secrets into POST and declare victory
POST /reset/new-password HTTP/1.1
Content-Type: application/x-www-form-urlencoded
new_password=...
The body is encrypted on the wire, but application frameworks, debug middleware and request-capture tools can still log it. Configure field-level redaction and disable body capture for authentication routes. Password managers and browser form behavior also require testing.
Redact at the earliest logging boundary
# Preserve route and safe keys; remove sensitive values.
/reset/confirm?token=[REDACTED]&campaign=mail
Prefer structured logs with an allowlist of safe fields over regular-expression cleanup after ingestion. Redact at CDN, load balancer, reverse proxy, application and tracing layers. Sampling does not make secrets safe; a sampled secret is still compromised.
Use opaque, scoped, expiring capabilities
token_record = {
"purpose": "password_reset",
"account_id": "usr_42",
"expires_at": "2026-07-27T15:20:00Z",
"used_at": null
}
A token should not embed unnecessary personal data. Give it enough random entropy, a single purpose, a short expiry and one-time atomic consumption. If a leaked link can change email, authenticate payments and reset a password, its scope is too broad.
Test privacy across the full request path
request_id=$(uuidgen)
curl --silent --show-error --location --header "X-Test-Request-ID: $request_id" "https://accounts.example.net/reset/confirm?t=TEST_SECRET_$request_id"
In a non-production environment, search authorized CDN, proxy, WAF, application, trace and analytics stores for the marker. Verify the clean redirect, cache headers, referrer policy and token invalidation. Remove the synthetic records according to test policy.
Use the correct threat statement
| Observer | Likely visibility |
|---|---|
| Passive network observer | IP, port, timing, sizes; often DNS/SNI hostname unless protected |
| TLS-terminating CDN or proxy | Full method, path, query, headers and body |
| Origin application | Full request after upstream processing |
| Browser/user profile | Address bar, history and page-visible fragment |
| Third-party page script | Whatever page policy and JavaScript access allow |
HTTPS encrypts the path and query on the network connection, but URLs are copied into many systems before and after that connection. Design every URL as metadata that may eventually be recorded.
Sources: the solved Stack Overflow question (question by Daniel Kivatinos; accepted answer by Marc Novakowski, CC BY-SA), RFC 8446 TLS 1.3, RFC 9849 Encrypted Client Hello, and RFC 9848 ECH discovery and DNS privacy considerations.
Primary source: Review the official reference ↗