DEV Community

Cover image for The Green Padlock That Almost Cost Me a Contract
Jean-Luc Martel
Jean-Luc Martel

Posted on

The Green Padlock That Almost Cost Me a Contract

Encryption is supposed to answer one question for the person sitting at the browser: am I really talking to who I think I'm talking to? On a corporate network running TLS inspection, the honest answer is often "not necessarily" — and most of the people relying on that network have no idea.

There are serious risks if the setup isn't done properly, but raising that flag can lead to uncomfortable discussions. I found that out the hard way, when demonstrating the problem nearly got my contract terminated.

The setup

The client ran a TLS inspection appliance on their internal network — the kind that decrypts outbound HTTPS so it can be scanned for malware and data loss before being re-encrypted and sent on. These devices are common and, in principle, defensible: most malware command-and-control and data exfiltration now hides inside TLS, so without inspection, a lot of security tooling is blind.

The way these appliances work is by man-in-the-middling every HTTPS connection. The appliance holds its own certificate authority. When you visit a site, it generates a certificate for that site on the fly, signs it with its own CA, and presents it to your browser. For this to work without warnings, that CA's root certificate is installed in the trust store of every managed machine — usually pushed automatically through group policy or device management.

Once that root is trusted, the browser stops complaining. The certificates the appliance generates look completely valid. No warning. No broken padlock. Nothing to tell the user their "encrypted" session is being read in clear text in the middle.

On top of that, the certificate issuance on this network was far more permissive than it should have been. The practical effect was that the internal CA could produce a trusted certificate for essentially any domain name — including public ones like google.com.

The problem I wanted to show

The thing I wanted the security team to see is subtle, and it's the part people consistently underestimate: once a root is trusted, the browser's special protections for high-value sites quietly stop applying.

Browsers do a lot to protect domains like google.com:

  • Certificate pinning ties those domains to a specific set of public CAs.
  • Certificate Transparency requires publicly trusted certificates to be logged in public, auditable logs.
  • HSTS forces connections to use HTTPS.

Every one of these makes an exception for locally installed roots. Pinning is skipped when the chain ends at an admin-installed CA. CT isn't required for private roots. HSTS is satisfied by any cert the browser considers valid. These exceptions exist on purpose — they're what stops a legitimate inspection appliance from breaking Google for the whole company. But they also mean that anyone who can issue from the trusted internal CA inherits all of that stand-aside treatment.

In other words: the protections you'd assume would catch an impersonated Google simply don't fire inside that environment.

The demonstration

To make this concrete rather than theoretical, I built a tiny proof of concept on my own machine:

  1. I created a web page that said, in plain text, "I'm a fake Google page." No login form, no attempt to harvest anything — the content existed only to make the point unmistakable.
  2. I added an entry to my own machine's hosts file pointing google.com at the IP serving that page.
  3. I generated a certificate for google.com from the environment's trusted CA.
  4. I loaded google.com in the browser.

The page loaded as google.com, with a green padlock, no warnings, and a certificate the browser reported as valid.

That was the whole point. The browser was not malfunctioning. It was doing exactly what the trust configuration told it to do. Every safeguard that should have flagged an impersonated Google had been designed to stand aside for a locally trusted root, and that's exactly what happened.

The hosts file was the deliberately contained part. It only affected my own machine — nobody else could reach that page. In a real attack, the hosts file stands in for an attacker's network position: a poisoned entry on the internal DNS resolver, ARP spoofing on a flat LAN, a rogue DHCP server, or a tampered proxy configuration. On a lot of internal networks, getting into that position is a lower bar than people like to assume. The demo swapped that step out for a one-line, single-machine change so there was no collateral effect at all.

The reaction

I sent the example to the security team as part of a technical debate about the risks of their setup. Their response was not to engage with the finding. It was to try to have my contract terminated, on the grounds that I had been "phishing."

I had not shared the fake page with anyone. There was no victim, no credential harvesting, no email, no deception of a single other person. The entire thing lived on one machine — mine — and demonstrated a property of their infrastructure. Calling it phishing was a category error, and I think a revealing one.

Why the reaction matters more than the bug

Phishing is the use of deception to trick a person into giving something up. A proof of concept that impersonates a site to no one but yourself, to demonstrate a flaw in a system you were engaged to assess, is the opposite of that: it's disclosure. The deception, such as it was, was aimed at a browser I controlled, to reveal something true about the environment.

What the reaction demonstrated is a failure mode I've seen more than once: when a finding is uncomfortable, it's easier to attack the method than to sit with the conclusion. The conclusion here was genuinely uncomfortable. It wasn't "the appliance has a bug." It was "the way trust is configured on this network means the guarantees your users assume they have — that a green padlock on google.com means they're talking to Google — don't hold, and an insider with issuance rights can impersonate anything to anyone, invisibly."

That's not a comfortable thing to hear about a system you own and defend. But shooting the person who showed it to you doesn't make it less true. It just guarantees the next person won't tell you.

What should have happened

The appropriate response to that demo was a conversation about controls, not contracts:

  • Keep the interception CA separate from the internal issuing CA, so a compromise of one doesn't hand over the other.
  • Apply name constraints to internal roots so they can only sign the domains they're supposed to.
  • Lock certificate profiles so requested names have to match the requester's identity, instead of allowing arbitrary domains.
  • Restrict and audit issuance — know who can request certificates and log everything that gets signed.
  • Protect the CA key properly, ideally in an HSM, because whoever holds it can impersonate anything to every managed device.
  • Be honest with users that inspection is happening, and keep sensitive categories like banking and health out of scope.

None of that is exotic. It's the standard hygiene for running TLS inspection without turning it into a single, silent point of total compromise.

The takeaway

The green padlock is a promise, and TLS inspection quietly rewrites the terms of that promise for everyone on the network. That can be done responsibly. But the first step is being willing to look at what your own configuration actually allows — especially when someone hands you an uncomfortable demonstration of it on a single contained machine, and asks you to think about it.

Attacking the messenger is a choice. It's just not a security control.

Top comments (0)