The Door Was Already Open: Two Critical IoT Exposures That Required No Exploit

The Door Was Already Open: Two Critical IoT Exposures That Required No Exploit

Water and energy telemetry from dozens of facilities. The real-time location of nearly a thousand vehicles. Two critical exposures that required no 0-day, no sophisticated exploit, and not even credentials.

During an authorized bug bounty program, I found two critical exposures inside the same IoT connectivity provider. The first allowed anyone on the Internet to read and write telemetry associated with water and energy infrastructure. The second exposed the real-time location and route history of nearly a thousand vehicles belonging to different organizations.

I didn't exploit a vulnerable version of anything. I didn't need a 0-day. I didn't even need credentials. The systems simply let me in. And both were running in production.

‍

A broker that trusted everyone

The first finding started with an MQTT broker.

MQTT is widely used to move telemetry between sensors, meters, controllers and other connected devices. In industrial environments, that can mean everything from water flow and reservoir levels to electrical consumption. This particular broker was exposed directly to the Internet over port 1883, which is already unusual for production. So I tried connecting without a username or password.

The broker responded: CONNACK, return code 0. Connection accepted.

That alone was a serious problem. Since Mosquitto 2.0, anonymous access isn't enabled by default. Someone had explicitly configured this broker to allow it. But being able to connect was only the beginning.

MQTT exposes internal broker statistics through the $SYS topic tree. Without authenticating, I could query them and see more than two million messages processed in production, along with dozens of retained messages. Then I subscribed to #, which in MQTT means: send me everything.

Within a few minutes I could see telemetry associated with dozens of facilities. Water flow, accumulated volume, reservoir levels, pH readings, voltage, electrical current, power consumption. The topic names made it possible to associate streams with individual installations. This wasn't test data. It reflected the operation of real water and energy infrastructure across multiple industries.

Then came the more serious question: could I also write?

I sent a harmless message to a topic created specifically for the authorized test. PUBLISH rc=0. Accepted. There were no ACLs preventing an anonymous client from publishing to other topics either. Together with the client, we validated that the telemetry belonged to facilities actually in operation and that anonymous writes were possible in the same environment.

At that point, the finding stopped being just about information exposure. The system was willing to trust data coming from an unauthenticated source on the Internet.

A technical finding can look very different once you translate it into a real scenario. Imagine an attacker publishing a normal-looking pH value while the actual measurement is outside the expected range. The dashboard continues showing a value that appears normal while the underlying condition is not. Or imagine someone collecting water and energy consumption patterns over time, patterns that reveal when a facility operates, when production slows down, and when it stops. Depending on how the telemetry feeds into other systems, manipulating values could also interfere with operational monitoring or with processes that rely on those measurements.

None of these scenarios begins with exploiting a software vulnerability. They begin with connecting to a service that should never have trusted an anonymous Internet client in the first place.

‍

Nearly a thousand vehicles on a map

The second finding was technically very different.

A fleet-management application embedded a third-party search service key directly in its public JavaScript. Having a key in the frontend isn't automatically a vulnerability. These services can use restricted keys specifically designed to operate from the browser. The problem was what this particular key was allowed to access.

It could list indexes that should never have been available to a public client. A users index with roughly 180 entries. A devices index with roughly 880. An events index with over 800,000.

Using the same key, I queried the devices index. The response contained nearly a thousand vehicles belonging to dozens of organizations. For each one, the available data included latitude and longitude, speed, IMEI, SIM identifier, organization, and historical events. There was no tenant isolation at this layer. One client's frontend credential could access data belonging to other organizations entirely.

And because the events index contained hundreds of thousands of historical records, it wasn't only possible to see where a vehicle was at a given moment. It was possible to reconstruct where it had been.

The exposed indexes also contained personal information and, in some cases, second-factor authentication seeds stored in cleartext.

Again, there was no complicated exploit. The credential was already being sent to every visitor's browser. It simply had far more access than it should have.

Coordinates in an API response can look like just another data point. Once you start connecting those coordinates over time, the picture changes. A live location tells you where an asset is right now. Historical locations reveal routes and routines. Repeated patterns can expose how an organization operates. At an individual level, location data can also reveal information about the people using those vehicles. The technical issue was an over-permissioned credential. The actual exposure was operational information from multiple organizations, accessible through a credential embedded in public JavaScript.

‍

The problem behind both problems

An MQTT broker and a search service used by a fleet-management platform don't have much in common technically. But the underlying security problem was remarkably similar.

In both cases, a service had more exposure than intended. Permissions were broader than necessary, trust boundaries weren't properly enforced, and the result was reachable from the Internet. Neither finding depended on an unpatched CVE or an unknown software flaw. Everything was working. It was just working under the wrong assumptions about who should be able to access what.

That distinction matters more than it might seem.

Security teams spend a lot of time tracking CVEs, patching software, and responding to newly disclosed vulnerabilities. All of that is necessary. But not every critical exposure has a CVE attached to it. Sometimes the software is fully patched and behaving exactly as configured. The configuration is the problem.

‍

The vulnerabilities nobody has to exploit

Both findings started with something simple: looking at how a system communicated and asking what it would let an external user do.

That's part of what makes exposures like these interesting from a pentesting perspective. There isn't always a vulnerable function waiting to be exploited. Sometimes the work is understanding the architecture, identifying where trust has been misplaced, and testing the assumptions behind it.

All the testing described here was authorized. Attackers don't have that constraint.

So the questions these findings left me with are straightforward. How many services are currently exposed to the Internet without anyone realizing what they actually allow? How many credentials have accumulated permissions nobody remembers granting? How many systems trust data simply because it arrived through the expected protocol, without checking who sent it?

We tend to think of a cyberattack as someone finding a way through a locked door. In these two cases, there was no lock to break.

The door was already open.

All testing described in this article was conducted as part of an authorized bug bounty program and reported through the appropriate channels. Hosts, credentials, organizations, identifiers and exact volumes have been redacted or modified to protect the affected parties.

‍