All articles
What a Packet Capture Can Prove
16 May 2026Security, Networking, TLS

What a Packet Capture Can Prove

Following a web request across VPN, TLS proxy and browser boundaries to distinguish observation from authority.

My network experiments began with tools that made communication visible. Netcat helped me think about a listener and a client; Nmap exposed how services appeared to another machine; Wireshark and tcpdump let me inspect traffic. I also explored interception tools, including Bettercap, Ettercap and mitmproxy, and the browser-focused BeEF framework within my own or controlled environments.

The useful distinction that emerged was between observing traffic and acquiring authority over it. A packet capture, a debugging proxy and JavaScript running inside a page can all expose information about a web connection. They do so from different positions, with different privileges.

My original account does not preserve captures, browser versions, certificate-store changes or reproducible attack traces. It supports the exploration, not a claim that I defeated TLS or compromised a browser. The following illustrative views separate those mechanisms at network, proxy and browser boundaries.

Follow the request, not just the interface

Suppose a browser reaches a website through a WireGuard tunnel. On the physical network, a capture can show the VPN endpoints, UDP traffic, packet lengths and timing. At an authorized tunnel endpoint, the corresponding virtual interface can expose the decrypted inner IP packets.

Wireshark showing a live packet capture with protocol detailsA capture shows what crossed one interface, from that interface's point of view. Screenshot: The Wireshark team (screenshot by VulcanSphere) / Wikimedia Commons, GPL

WireGuard's interface model makes this distinction explicit: authenticated packets are decrypted and accepted onto the tunnel interface according to the peer's allowed addresses. Its protocol documentation specifies UDP transport.

“Decrypted” here describes the VPN layer. If the inner packet carries HTTPS between the browser and a separate web server, its TLS-protected content remains encrypted. The VPN endpoint has removed one layer of protection; it has not thereby acquired the web connection's traffic secrets.

The same request can therefore appear as encrypted WireGuard traffic on one interface and identifiable inner traffic on another, while its HTTP content remains unavailable in both captures. This is a consequence of nested protocols, not inconsistent behavior by the capture tool.

The transport also needs to be identified rather than assumed. An ordinary TLS-over-TCP connection is one useful reference case, but HTTP/3 maps HTTP over QUIC. Finding UDP traffic does not establish that the application is unencrypted, just as finding TCP does not establish which application or security properties it carries.

A packet is not an HTTP request. Segmentation, retransmission and multiplexed application traffic complicate that relationship. Counting packets or noticing a burst can establish a traffic pattern; identifying the user's precise action requires additional evidence.

Encryption changes visibility, not every observable

TLS protects application content while leaving information necessary to carry the connection across the network. An observer may still see network endpoints, lengths and timing. Name visibility depends on the protocols and vantage point.

A plaintext DNS query can disclose a destination name. An ordinary unencrypted TLS ClientHello can disclose the Server Name Indication, or SNI. But “HTTPS always reveals the hostname” is too broad.

Encrypted Client Hello, standardized in RFC 9849 in March 2026, protects the inner ClientHello, including SNI and potentially sensitive negotiation fields. The standard also explains its limits: visible IP addresses, plaintext DNS and other channels can still reveal the destination. Shared infrastructure can create an anonymity set, but its externally visible configuration affects how much ambiguity remains.

Even finding an ECH extension in a capture does not prove successful use. The protocol includes GREASE behavior that sends a synthetic extension to keep the ecosystem tolerant of it. A careful analysis needs evidence of the negotiated behavior, not a field name in isolation. This is current protocol context, not a claim about what was deployed during my earlier experiments.

Endpoint access changes the picture again. Wireshark can decrypt TLS when supplied with appropriate session secrets. A matching capture and secrets exported by an authorized endpoint can make HTTP visible without altering the network exchange. The older technique of supplying a server RSA private key has narrower applicability and does not decrypt TLS 1.3 in that way.

Thus “Wireshark displayed the request” is incomplete evidence. It matters whether the capture contained cleartext HTTP, whether an endpoint supplied session secrets, whether a proxy terminated TLS, or whether the display was showing traffic inside another tunnel. Each explanation implies a different security boundary.

A hostile route does not supply a server identity

An active adversary can sometimes redirect, delay or block traffic. Those capabilities do not automatically supply the cryptographic identity that a correctly validating TLS client expects.

In an ordinary certificate-authenticated TLS 1.3 handshake, several checks work together. The certificate chain connects a public key to a trusted certification path. Service-identity matching checks whether the presented identity corresponds to the destination the client intended to reach. The server's CertificateVerify signature proves possession of the corresponding private key and binds that proof to the handshake transcript. Finished provides keyed confirmation and handshake integrity. The subsequent record protocol uses authenticated encryption.

These roles are described separately in TLS 1.3 and Service Identity in TLS. They explain why encryption alone is an incomplete description of HTTPS.

For example, directing a request for accounts.example to another IP address does not make a certificate for unrelated.example valid for it. The expected service name must not silently become whatever name an untrusted routing or resolution result supplies. Conversely, a correctly authenticated connection to a deceptive domain does not establish that the domain represents the organization the user had in mind.

The protection is specific. It assumes correct validation, appropriate trust anchors and uncompromised endpoints and keys. It does not prevent denial of service or make the application trustworthy. It also does not authorize every action carried through the encrypted channel.

A debugging proxy changes who is trusted

Mitmproxy provides a particularly clear way to understand the difference between passing traffic and terminating it. Its certificate documentation describes the prerequisite: the client must trust the proxy's certificate authority for generated interception certificates to be accepted.

The resulting arrangement has two TLS connections:

The browser holds TLS session A with a trusted proxy, which sees plaintext and holds a separate TLS session B with the origin serverA trusted debugging proxy terminates one TLS session and opens another. Diagram: Daniel Buttigieg

The browser validates the proxy-issued certificate for the requested service. The proxy decrypts that connection, processes the HTTP exchange and establishes another TLS connection upstream. The proxy can see the content because it is an endpoint entrusted with it.

This is materially different from an arbitrary observer recovering an established connection's keys. Adding a certificate authority changes the client's trust policy. Applications with different trust stores or additional certificate restrictions can behave differently.

The two-session model also exposes a less obvious failure: the browser's successful validation of TLS A does not independently prove that TLS B was validated correctly. The proxy has inherited responsibility for checking the origin. If it accepts an invalid upstream certificate and still serves the browser a locally trusted certificate, the browser-facing connection can appear acceptable while the original server-authentication requirement has failed.

That is a concrete reason to test a proxy's rejection behavior, rather than treating its ability to display plaintext as the complete result.

Durumeric and colleagues examined this responsibility in The Security Impact of HTTPS Interception, presented at NDSS 2017. Their trial-product tests, conducted in January–March 2016, challenged certificate validation with expired, self-signed and incorrectly signed certificates, alongside protocol and cipher tests. Of twelve tested middleboxes, five received their severe-vulnerability classification; three had broken certificate validation. Those are distinct findings.

The study also used server-side handshake fingerprints to infer interception. That method could miss proxies that copied browser behavior, and depended on assumptions about the reported browser identity. Its historical products, traffic populations and grading scheme cannot establish today's prevalence or rank current products. Its enduring contribution here is the demonstrated need to examine the security properties of the replacement connection.

Transport policy addresses another part of the path. For a known HSTS host, HSTS requires HTTPS upgrading and termination on transport-validation errors. A redirect sent over an actual unprotected HTTP connection cannot itself authenticate that initial exchange. But HSTS does not remove a certificate authority that the client already trusts: a proxy-issued certificate accepted under that policy need not produce a validation error. HTTPS enforcement and decisions about trusted issuers are related controls with different jobs.

The browser is an endpoint with its own authority

After TLS delivers a page, the browser interprets it. Transport authentication does not distinguish intended application code from code introduced by an application vulnerability.

For ordinary HTTPS documents, the HTML origin model distinguishes scheme, host and effective port. Two paths on the same origin do not create separate security principals. Changing the host or effective port ordinarily does.

Consider these illustrative HTTPS locations, with each port shown explicitly:

HostEffective portPathSame origin as the first row?
app.example443/accountYes
app.example443/helpYes
api.example443/accountNo
app.example8443/accountNo

The path changes without changing the origin; the host and effective port do not.

Code included in the page can acquire that document's authority. An external classic script is not automatically isolated under the hostname from which its source was downloaded. The HTML algorithms fetch the script using the document's settings and create and run it in the associated realm. An application that admits attacker-controlled script into its own execution context has already crossed an important boundary.

That explains how cross-site scripting can remain serious on a site delivered entirely over HTTPS. TLS can faithfully protect the delivery of a response that the application has constructed unsafely. The script then operates inside the origin; it need not defeat network encryption to interact with the page.

My exploration of BeEF belonged to this browser-security question. The framework describes its focus as the browser context. Using or understanding such a framework does not by itself demonstrate an operating-system compromise, a browser sandbox escape or access to unrelated sites' passwords. Those outcomes require their own mechanisms and evidence.

Reading a credential and using a session are different

Cookie protections make the origin boundary more concrete. HttpOnly excludes a cookie from script-facing cookie APIs. It does not mean the browser stops attaching that cookie to otherwise eligible HTTP requests.

Consider an illustrative application in which a session cookie is HttpOnly and a user is allowed to update a preference:

script cannot read the session cookie
    -> browser can still attach it to an eligible same-origin request
    -> server authenticates the session and evaluates the requested action

Malicious script executing with the application's origin authority may therefore perform actions or read accessible responses without extracting the cookie value. The server's authorization rules still limit the account, and additional confirmation requirements may constrain particular actions. HttpOnly closes one route to credential exposure; it does not make arbitrary same-origin code harmless.

CORS governs a different decision. The Fetch standard specifies how responses can be shared across origins and when a preflight is required. Some requests can reach a server even though the browser refuses to expose their responses to the calling script. Other requests may be stopped before the actual request because preflight fails. A console CORS error alone therefore cannot establish that the server received nothing or changed no state.

Neither response-sharing policy nor TLS replaces server authorization. A useful assessment has to identify the actual operation, credentials, origin, browser restrictions and server-side result.

Content Security Policy can constrain script execution and other resource behavior. The CSP Level 3 editor’s draft describes it as defense in depth, rather than a replacement for safe handling of untrusted content. It also distinguishes an enforced policy from Content-Security-Policy-Report-Only, which monitors violations without blocking them. The existence of a policy header is weaker evidence than observing that the relevant rule is enforced.

An observation needs a control

A stronger continuation of my original experiments would preserve the evidence needed to distinguish these cases. With disposable clients, synthetic data and systems I control, the same benign request could be followed across a physical interface, a tunnel interface, an authorized TLS-decoding view and browser developer tools.

The record would need the actual route, interface, browser and tool versions, proxy configuration, relevant trust state and whether session secrets were available. A successful decoding view should be paired with a control that confirms the capture covers the intended flow. Otherwise, failing to see a plaintext marker might simply mean inspecting the wrong connection.

The proxy test should first succeed against the controlled upstream with a valid certificate. Changing that certificate to a designated invalid case should then produce an attributable validation failure in the proxy diagnostics, without forwarding the origin’s response as authenticated content. A generic connection failure or a trusted browser-facing certificate would not establish that rejection. Browser-origin tests need both the script's visible behavior and the server's recorded result, since a blocked response is not proof of a blocked request.

These are proposed experiments, not recovered results from my earlier work.

The lesson I can defend is a habit of locating authority. When a request becomes readable, identify which layer ended and which secrets or trust decision made it readable. When content executes, identify the origin and permissions it acquired. That turns “the traffic was intercepted” into a technical claim that another person can actually examine.


Image credits