blog.evan.lat (corporate-friendly)

security research & vulnerability analysis — main site at evan.lat. pgp for sensitive stuff: here.

The Weakest Link: Breaching Enterprise Infrastructure Through Contractor Misconfigurations

The single most reliable way to breach a large organization isn’t to attack the organization directly. And honestly? That’s a paradigm shift in how most people think about enterprise security. It’s not the fortress that fails first — it’s the contractor they hired to build something internal, the subsidiary they acquired and half-integrated, the vendor who has privileged access to their systems and a much smaller security team. Every prominent company is surrounded by a constellation of smaller entities that quietly touch their data — and those smaller entities almost never get the same scrutiny. The throughline across every large-organization breach I’ve looked at is the same: the perimeter wasn’t where anyone thought it was.

Here are two recent examples. Both worth sitting with.


Case 1 — The International Organization With a Firebase Problem

This was a fairly prominent organization with international operations and a dedicated infrastructure division. They’d outsourced a significant portion of their development work to contractors — and this became obvious, comprehensively, the moment I looked at the code. At its core, this is a story about what happens when you leverage external teams without establishing a robust security baseline.

Their staff portal sat behind a login screen — no self-registration, subdomain suggested it was internal-only:

The source of the login page shed light on everything immediately:

Firebase configuration, fully exposed. Running firepwn against it confirmed the database was accessible — but enumerating the usual collection names came up empty:

So I tried something simpler: creating an account. And it worked.

Logging in with those credentials didn’t give Firebase access, but it did log me into their partner portal. Here’s where it gets interesting. One of the first things I found was a user search feature. The right question — the load-bearing question — was “what does this endpoint actually return?” Querying a single character — just a, just e — returned hundreds of records from their REST API. Each one included:

  • Date of birth
  • Country and place of birth
  • Nationality
  • Email address
  • First name, last name, preferred name
  • A unique identifier and its issue date

To put that concretely:

There was no pagination limit worth mentioning, no rate limiting, no access control differentiating what an unauthenticated-but-registered user could see versus what a staff member could see. Anyone who could create an account — which anyone could — had access to the personal details of every user in the system. It’s not just an IDOR — it’s a holistic failure of the assumption that “login” implies “authorization.”

The organization was notified, the portal’s Firebase backend was taken offline, and the issue was remediated.


Case 2 — The Contractor, The Exposed Bucket, and the SQL Injection Buffet

This one started with an accidental discovery — I’d scrolled too far through FOFA and Netlas results and quietly stumbled across an exposed TeamCity CI server belonging to a contractor that did IT infrastructure and CRM work for several larger companies. I couldn’t get into it, but the name of the company led me to GreyHatWarfare, where I searched for associated S3 buckets:

An unauthenticated listing:

$ aws s3 ls s3://[redacted] --no-sign-request
artif
img
backups
[redacted]
redactedsvc
local

Most of it was noise. The backups directory was not. Running TruffleHog against the bucket came up mostly empty — one PlanetScale API key with nothing but test data. But extracting the ZIP from backups revealed a sizeable PHP codebase:

I opened it in VS Code and searched for "SELECT. The results were immediate and alarming:

Three SQL injection vulnerabilities in the first pass, with more obvious ones scattered throughout — the landscape here was genuinely transformative in how bad it was:

In the above, $status flows directly into a query and is influenced by user-supplied input. This endpoint required authentication — but AccountReset.php made authentication a formality. Let me surface what the actual “protection” looked like:

<?php
    include('./../common/header.php');
    include('./../config.php');

    authCheck();
    // $username = urldecode($_POST['username']);
    // ...
    
    if ($resarr['statuscode'] == "no_auth" || $resarr['statuscode'] == 'nadmin' || $resarr['statuscode'] == "ERROR") 
    {
        <script>
            alert("Unauthenticated.");
            history.back();
        </script>
    }
    // ...
    // password reset logic executes regardless
    echo json_encode($result_array); 
?>

The tell is in the “block.” The authentication check outputs a JavaScript alert and calls history.back() — client-side only, with no server-side short-circuit. The password reset logic runs regardless of the auth check result. The intended “block” is literally just a popup that any direct API call, curl command, or JavaScript-disabled browser would sail straight past. It’s not authentication — it’s theater. And honestly? It’s the most load-bearing kind of theater: the kind that makes the team feel protected while fostering a false sense of security.

The attack path from here was straightforward:

  1. Find a staff account via the exposed codebase or enumeration.
  2. Use the broken auth endpoint to reset their password.
  3. Log in and leverage the SQL injection to dump the database.

I reported it. The backups directory disappeared from the public bucket about twelve months later, with no reply. The SQL injections presumably still exist in whatever they’re running. That’s the landscape when the contractor’s infrastructure is the weakest link — the exposure quietly persists, unaddressed, doing the heavy lifting of being someone’s future incident.

← back