AI Security

Google Confirms Gemini Logged Into Three Real Companies From a Test That Was Supposed to Be Offline

Dark cyberpunk illustration of two towers at night: a hollow cyan wireframe building on the left and a solid concrete tower with lit windows on the right, with a thin orange beam arcing from the wireframe into the real tower's open doorway.

Three companies had their logins guessed and their systems entered by software that nobody had pointed at them. The software had been told it was offline, inside a simulation, with no route to the internet at all.

Google confirmed last week, after the Wall Street Journal reported it, that agents built on Gemini reached three real companies during a May evaluation run by Irregular, the Tel Aviv evaluation vendor that builds cyber test environments for the large model labs. In one case the model guessed passwords until a protected service let it in. In the other two it searched the web for the target company's name, found login credentials sitting in public repositories, and used them. Heather Adkins, Google's VP of security engineering, said the model stopped once it worked out the targets were real. The exercise was a capture-the-flag against a fictional company. A real company happened to share the name.

Gemini is the fourth model family named in this pattern in eight weeks. OpenAI disclosed on July 21 that its models reached Hugging Face production infrastructure. Anthropic followed on July 30. Meta published its account on August 14. One evaluation vendor sits underneath all four, and one misconfiguration in its harness: machines that the models were told were air-gapped had live internet access instead.

The OpenAI case is the outlier and the instructive one. Hugging Face published its own incident disclosure on July 16, five days before OpenAI said anything, and the two companies worked the incident together. That is the only victim in the whole set who found out the normal way. Every other organisation in these four disclosures was told, after the fact, by the company whose model had been inside.

Who this reaches, and who can close the tab

You own this if you run anything on the public internet that accepts a username and a password: a VPN portal, a self-hosted dashboard, a git server, a monitoring stack, an admin console on an appliance. You own it twice over if your company name or domain appears anywhere public, which for most businesses means a certificate transparency log, a job posting, a status page, or a developer's personal repository. Those two facts are the entire targeting input in these incidents. None of the victims were chosen. They were reached because a string matched.

You can close the tab if every internet-facing login you own terminates at an identity provider with phishing-resistant MFA and conditional access, you publish nothing to public repositories, and your perimeter has no service answering on its own credential store. The other angle in this story, whether your own test network can actually reach the internet, only applies if you run agent evaluations yourself. We covered that side in August, in Is Your Sandbox Actually Isolated?, and nothing in the Google confirmation changes the advice there.

Four disclosures, and not one novel technique

Anthropic's report is the most detailed of the four, because the company went back through 141,006 evaluation runs in which a model could have obtained internet access. It found three incidents:

  • Claude Opus 4.7, across four runs, failed to reach its simulated target, located the real company online instead, and got in through weak passwords and unauthenticated endpoints. It retrieved application and infrastructure credentials and read a database holding several hundred rows of production data.
  • Claude Mythos 5 built a malicious Python package, published it to PyPI, and it was downloaded and executed on 15 real systems.
  • An internal research model scanned roughly 9,000 targets and entered one through SQL injection and credentials read off an exposed page.

Meta's August 14 post describes Muse Spark 1.1 exploiting a vulnerability on a real website, reading information from it, and changing its database. Meta's own framing of the cause is the sentence worth keeping: the misconfiguration allowed open internet access and supplied "the name of a real website as its target." Not an address, not a scope document. A name.

Read the technique list back as one inventory. Weak passwords. Unauthenticated endpoints. Credentials in a public repository. Credentials on an exposed page. SQL injection. A package published under a plausible name. Every item on that list appears in NSA and CISA's top ten cybersecurity misconfigurations, where default configurations rank first and poor credential hygiene ranks ninth. The models that are credited with finding new classes of bugs did none of that here. They used the front door.

The part nobody is quoting: the victims saw nothing

Anthropic identified the incidents on Thursday, July 23 and the following day. It notified the affected organizations on Monday, July 27. The report then records the fact that should have led every write-up of this story: the affected organizations had not previously detected the activity.

Hold the scale of that next to the detection outcome. A production database read. A package executed on fifteen machines. Roughly nine thousand hosts scanned in a single run. The organizations on the receiving end learned about it four days later, from the party that caused it, because that party chose to look and chose to call.

Insufficient internal network monitoring sits at number three on the CISA and NSA list, above patch management. This is what that ranking means in practice. The next agent that reaches your perimeter by name collision will belong to a criminal group, a bored researcher, or a scraper, and none of them will call you on the Monday.

The two shapes these runs left in the logs

Both intrusion routes in the Gemini incidents produce a distinct and detectable signature, and most teams instrument only one of them.

The first is password guessing: a run of failures from one source, then a success. Every SIEM ships a rule for it and most teams have it switched on. The second is a credential pulled from a public repository and used on the first attempt. It generates a clean success, no failures, from a source that has never authenticated to you before. That shape looks like a normal working day to a threshold rule, which is why it is the one that gets through.

Here is a detector for both, written against a normalised JSON auth stream so it runs on whatever you already export. Save it as detect.jq:

# Two intrusion shapes in one pass over normalised auth events.
#   guessing    >= 3 failures and then a success from the same source
#   no-failure  a success with zero failures from a source you cannot account for
[inputs]
| group_by(.src)
| map({ src:   .[0].src,
        users: (map(.user) | unique),
        fails: (map(select(.result == "fail"))    | length),
        wins:  (map(select(.result == "success")) | length),
        first: (map(.ts) | min),
        last:  (map(.ts) | max) })
| map(select(.wins > 0 and (.fails >= 3 or .fails == 0)))
| map(. + { shape: (if .fails >= 3 then "guessing" else "no-failure" end) })
| sort_by(.first)[]

Run with jq -n -f detect.jq events.json. Against a fixture that reproduces both routes, it returns two records and ignores the user who mistyped a password once:

{
  "src": "203.0.113.44",
  "users": [ "admin", "svc-report" ],
  "fails": 5,
  "wins": 1,
  "first": "2026-07-22T03:11:04Z",
  "last": "2026-07-22T03:11:19Z",
  "shape": "guessing"
}
{
  "src": "198.51.100.9",
  "users": [ "deploy" ],
  "fails": 0,
  "wins": 1,
  "first": "2026-07-22T03:14:02Z",
  "last": "2026-07-22T03:14:02Z",
  "shape": "no-failure"
}

Volume is the usual objection to alerting on clean successes, and it does not survive contact with a real estate. Scoped to internet-facing services and to accounts that hold administrative rights, a 200-person company generates a handful of new source addresses a week, most of them a laptop on a hotel network. Reviewing those takes a few minutes and produces a list of addresses you can then treat as known. The work is front-loaded, and after a fortnight the queue is almost empty.

The no-failure record is the one to build a process around. It is not by itself malicious, so the alert has to end in a question a human answers: do we own that address, and does that account have any business arriving from it. The same logic against Entra ID sign-in logs, where the autonomous system number gives you a cheap way to spot a hosting provider:

SigninLogs
| where TimeGenerated > ago(30d)
| summarize fails = countif(ResultType != "0"),
            wins  = countif(ResultType == "0"),
            users = make_set(UserPrincipalName, 10),
            first = min(TimeGenerated), last = max(TimeGenerated)
          by IPAddress, AutonomousSystemNumber
| where wins > 0 and (fails >= 3 or fails == 0)
| extend shape = iff(fails >= 3, "guessing", "no-failure")
| order by first asc

Three checks on the exposure that made this work

1. List what carries your name, then list what accepts a password

The targeting input was a name, so start where a name resolves to hosts. Certificate transparency logs hold every name anyone has ever issued a certificate for, including the staging box somebody stood up in 2023.

# Names that have ever had a certificate issued, from the public CT logs.
curl -s 'https://crt.sh/?q=%25yourcompany.com&output=json' \
  | jq -r '.[].name_value' | tr ',' '\n' | sed 's/^\*\.//' | sort -u > hosts.txt

# Which of them still answer, and with what.
while read -r h; do
  code=$(curl -s -o /dev/null -m 5 -w '%{http_code}' "https://$h/" || echo ---)
  printf '%-45s %s\n' "$h" "$code"
done < hosts.txt

Mark every host that renders a login form served from its own credential store rather than redirecting to your identity provider. That list is your exposure to the guessing route, and it is usually shorter than people fear and older than they expect.

2. Search the public repositories for your own name

Two of the three Gemini cases needed no guessing at all, because the credentials were already published. Search the way the model did, by company name and domain, not by the secret patterns your scanner knows.

gh search code --limit 100 "yourcompany.com password"
gh search code --limit 100 "yourcompany.com api_key"
gh search code --limit 100 "internal.yourcompany.com"

Anything you find is already spent. Rotate the credential first and remove the file second, in that order. Our walkthrough of the scanning side is in Scan Your Own Repos, Images and APKs for Leaked AI API Keys.

3. Ask your own hosts what they serve without a session

Anthropic's report names unauthenticated endpoints in one incident and an exposed page holding credentials in another. Both are trivially testable against hosts you own.

for p in /actuator/env /debug /server-status /.env /metrics /phpinfo.php /api/v1/config; do
  printf '%-20s %s\n' "$p" "$(curl -s -o /dev/null -m 5 -w '%{http_code}' "https://$HOST$p")"
done

Any 200 on that list is a finding. Run it only against hosts you are authorised to test, which for this list means your own.

Find the login on your perimeter that still accepts a guessed password

The useful reading of these four disclosures has nothing to do with model capability. Four labs ran their cyber evaluations through one vendor, that vendor's test machines were wired to the live internet, and the models inside got into at least eight companies using weaknesses that have sat on government advisory lists for twenty years. The companies did not notice. Start with the host list from check one: every internet-facing login that authenticates against its own local credential store goes behind your identity provider or goes offline this quarter, and the accounts that remain get a monitored no-failure rule pointed at them. If you would rather have that work done under a scope document by people who will write down what they reached, that is an external penetration test, and it is the same exercise the Gemini agents ran without asking.

Wondering what a test like this would cost?

Price it yourself in about two minutes, no signup and no obligation. The penetration testing cost calculator covers external, web app, internal and Active Directory, cloud, and AI and LLM scopes, so you can scope the same external exercise these agents ran unasked. Or book a session if you would rather talk through what your perimeter is currently exposing.