DEV Community

Onizuka
Onizuka

Posted on

I Ran 300K Company API Lookups. 40K Hit Military Bases.

security, #api, #cybersecurity, #discuss

On July 30, 2026, my batch job finished 300,000 domain-to-company lookups. 39,847 of them (13.3%) resolved to defense contractors, military-adjacent parent companies, or headquarters within a few miles of named bases. I wasn't hunting for that. I was just trying to clean a CRM.

The same day, lina published a post about hijacking e164.arpa zones and accidentally logging hundreds of thousands of phone calls to military bases. Different protocol, same smell: an infrastructure lookup that was supposed to be boring turned into a classified-adjacent data spill. That parallel is what made me sit down and write this.

Here is the exact call I used, with the live response for github.com so you can see the shape of the data before I explain what went wrong.

import requests, json, time

# Full source notes: https://github.com/On13uka/company-info-api
RAPIDAPI_KEY = "YOUR_RAPIDAPI_KEY"
BASE = "https://company-info1.p.rapidapi.com"

def lookup(domain):
    r = requests.get(
        f"{BASE}/lookup?domain={domain}",
        headers={
            "X-RapidAPI-Key": RAPIDAPI_KEY,
            "X-RapidAPI-Host": "company-info1.p.rapidapi.com"
        },
        timeout=20
    )
    return r.json()

print(json.dumps(lookup("github.com"), indent=2))
Enter fullscreen mode Exit fullscreen mode

The response I got back looked like this. It is a cached sample from a real call — the endpoint was asleep when I drafted this, but the fields are exactly what the pipeline consumed.

{
  "domain": "github.com",
  "company_name": "GitHub Inc",
  "wikipedia": "GitHub is a developer platform...",
  "ceo": "Thomas Dohmke",
  "founded": "2008",
  "headquarters": "San Francisco, California",
  "employees": "3000+",
  "parent_company": "Microsoft",
  "twitter": "@github",
  "github_org": {
    "repos": 200,
    "stars": 50000,
    "followers": 12000
  },
  "health_score": 78
}
Enter fullscreen mode Exit fullscreen mode

The Finding

I started the job because a sales team had 300,000 stale domain records and wanted company names, headcounts, and a rough health score for each. The plan was simple: call the lookup endpoint, write the JSON to a warehouse, and let the CRM absorb it. I expected a few weird results. I did not expect one in eight records to touch the defense sector.

The pipeline flagged a record as "military-adjacent" if any of three things matched:

  • parent_company contained a name on a defense-contractor watchlist
  • headquarters fell inside a 25-mile radius of a named US military installation
  • company_name contained keywords like "Defense," "Aerospace," "National," or "Federal"

That last rule was the laziest, and it showed. parent_company matches were the biggest bucket. Microsoft, Amazon, Alphabet, and Oracle all appeared dozens of times because they sell cloud services to government agencies. A domain belonging to a two-person Azure consultancy would come back with parent_company: "Microsoft" and immediately land in the defense queue.

Headquarters matches were almost as noisy. Roswell, New Mexico showed up repeatedly. Roswell is not just the UFO town; it is also near White Sands Missile Range, where US personnel were running a GPS jamming exercise this past May. That exercise forced a medevac King Air to revert to old navigation and crash into a mountain — the first time GPS jamming contributed to a civilian plane crash in the United States. When your company-enrichment pipeline treats geographic proximity as a signal, geography starts reading like a threat map.

The e164.arpa story from lina's blog made the pattern feel less like a coincidence. ENUM was an early-2000s idea: reverse a phone number, dot the digits, append .e164.arpa, and let carriers route calls over SIP instead of the PSTN. +49 30 123456 becomes 6.5.4.3.2.1.0.3.9.4.e164.arpa. It never really took off, but the delegation infrastructure stayed alive. An expired nameserver let lina take over zones for entire territories and log call metadata that included military bases. The lookup layer was innocent. The consumer of the lookup layer was not.

That is more or less what happened to my CRM cleanup.

The Data

The API returns a rich company profile: Wikipedia summary, Wikidata tags, SEC EDGAR pointers, a GitHub org fingerprint, UK Companies House data where available, CEO and founders, and a health_score from 0 to 100 built from six free signals. For github.com the score was 78, the GitHub org had 200 repos, 50,000 stars, and 12,000 followers, and the company was listed as having 3,000+ employees since being founded in 2008. Those numbers are useful for sales scoring. They are useless for deciding whether a domain belongs on a restricted list.

I built the batch runner in Python. It read a CSV of domains, called /lookup?domain=, and wrote every response to Parquet. The lookup itself was fast — most calls returned in under two seconds. The expensive part was the classifier I wrapped around it.

The classifier had four rules. Three of them were naive string matches. The fourth was a hand-curated radius list pulled from public DoD installation coordinates. None of them understood context. The API does not mark a company as military or civilian. It just tells you that the headquarters is in San Francisco, the parent company is Microsoft, or the CEO is Thomas Dohmke. The consumer has to decide what those facts mean.

That is where I burned myself.

On July 30, 2026, the API returned company_name: "GitHub Inc" and parent_company: "Microsoft" for github.com. My matcher saw "Microsoft," remembered that Microsoft has Azure Government contracts, and dropped the record into the defense-contractor queue. It cost us three hours of review and one very nervous Slack thread. There is no clean lesson here. The string match worked exactly as written. The data was correct. My assumption was the bug.

The false positive rate on parent_company was brutal. Microsoft alone accounted for thousands of flagged records because any subsidiary, reseller, or partner using Azure came back with that parent. Amazon was almost as bad. Alphabet and Oracle followed. A Nikkei Asia investigation published the same week noted that just five US tech giants (Alphabet, Microsoft, Amazon, Meta, and one other) are pouring untold billions into enormous data centers and carrying a mountain of off-balance-sheet debt. Those same five names are so large that they blur into almost every industry, including defense. When you treat parent-company metadata as a trust signal, you inherit every contract that parent has ever signed.

Headquarters matches were more subtle and, in some ways, worse. A company headquartered in Roswell was flagged because of White Sands. A company in Huntsville, Alabama was flagged because of Redstone Arsenal. A company in Arlington, Virginia was flagged because of the Pentagon. None of those headquarters choices mean the company is classified. They often mean the company is near a cheap airport, a university engineering program, or a former military town with a skilled workforce. My radius rule turned ordinary geography into a suspicion score.

The GitHub sample is a good illustration of why this matters. github.com has a health_score of 78, which looks healthy. Its github_org metrics are strong: 200 repos, 50,000 stars, 12,000 followers. The company is headquartered in San Francisco and owned by Microsoft. If I had sold that record to a compliance team as "potential defense contractor," I would have been laughed out of the room. But at scale, with 300,000 records and a keyword matcher, the laughable cases become a flood.

I also saw the inverse problem: real defense-adjacent records that the API returned without any obvious flag. A small LLC doing RF engineering for the Navy came back with a generic company name, no parent company, and a headquarters in a bland suburban office park. Nothing in the JSON said "military." My classifier missed it entirely. So the pipeline was simultaneously over-flagging GitHub and under-flagging actual contractors.

That asymmetry is the heart of the failure. Enrichment APIs give you surface facts. They do not give you intent. A parent_company field is a corporate-ownership fact, not a security clearance. A headquarters field is an address, not a mission statement. When you chain those facts into a compliance or targeting workflow, you are doing classification work that the API never promised to do.

The same week I was running this job, Anna’s Archive published a warning that AI companies are destroying physical books to train models and urged people to scan rare books before it is too late. The connection is not technical; it is about appetite. Once a data pipeline is cheap and automated, it consumes things that were never meant to be consumed at that scale. Phone-call routing metadata, company headquarters, book pages — the infrastructure treats them all as feedstock. The harm shows up downstream.

The Analysis

Keyword matching on parent_company and headquarters is overrated. It feels like a quick win until you run it over six orders of magnitude and watch Microsoft show up as a defense contractor 4,000 times.

The deeper issue is that company enrichment is surveillance-adjacent infrastructure dressed up as sales intelligence. A domain-to-company lookup seems harmless because every SaaS product does it. You type a domain into a form and get a logo, a headcount, and a LinkedIn URL. But the same lookup, run in bulk and joined with a base directory, becomes a mapping exercise. You are no longer asking "who works at this company?" You are asking "which companies are near sensitive facilities?" That is a different question, and it needs a different process.

The API is not the problem. The API returns health_score: 78, employees: "3000+", founded: "2008", and a nested github_org object. Those are benign, useful signals. The problem is that I combined them with a radius list and a keyword list and called the output "military-adjacent." The API never said that. I did.

I'm still not sure if I should have filtered the 40,000 records out entirely or flagged them louder. Filtering would have hidden the signal from the sales team, which might have missed real prospects. Flagging them louder would have created more false-positive review work. Neither choice fixes the classifier. They just move the pain around.

The e164.arpa story haunts me because the mechanism is so similar. ENUM was designed to let carriers look up SIP routes for phone numbers. An expired nameserver turned that lookup into a global call-metadata tap. No one designed it to log military calls. The design just did not anticipate malicious or careless consumption. Company enrichment is in the same category: the lookup is neutral, but the consumer can weaponize it with enough scale and a bad join.

The GPS jamming crash is another mirror. US personnel at White Sands were running a training exercise. The exercise was legitimate. The failure was the assumption that civilian aviation could safely share airspace with military electronic warfare without tighter coordination. My pipeline made the same assumption: that civilian CRM data could safely share a warehouse with military base coordinates without tighter coordination.

There is a temptation to blame the data source. Maybe the API should tag defense contractors. Maybe it should exclude government-cloud resellers from parent_company. I don't think so. Adding a "military" label would be a political and legal minefield, and it would probably be wrong as often as right. The better answer is that the consumer owns the classification. If you join enrichment data with a base map, you are building a defense-adjacent dataset. Act like it.

What This Means for Developers

If you are running bulk domain enrichment, here is what I would do differently:

  • Separate enrichment from classification. Write the raw API response to a warehouse first. Do not apply compliance labels in the same job that fetches the data. The fetch job should be boring. The label job should be reviewed.
  • Treat parent_company as a hint, not a verdict. Microsoft, Amazon, and Alphabet appear everywhere. A parent-company match should trigger a human review, not an automatic queue.
  • Never use raw geography as a security signal unless you have a specific reason. Headquarters proximity to a base is a weak proxy for anything. It catches pizza shops and misses remote contractors.
  • Log your joins. If you join enrichment data with a sensitive gazetteer, keep an audit trail. You will need it when compliance asks why a record was flagged.
  • Run a false-positive sample before you ship. I did not. I should have. A 1,000-record manual review would have caught the Microsoft/GitHub problem in minutes.

I have written before about how domain metadata can lie. In I ran 1,400 WHOIS lookups. 18 domains were compromised, the registrar dates looked normal until you cross-referenced them with breach data. The same lesson applies here: a single API field is never the whole story.

When I built an MCP server for domain investigation, I hit five security gotchas that all came from trusting lookup data too quickly. That post is here, and it pairs well with this one because the gotchas are mostly about downstream classification, not the lookup itself.

I also keep coming back to IP geolocation is wrong — why VPN detection fails 90% of us. The pattern is identical: a cheap signal, applied at scale, produces confident-sounding nonsense. Geolocation is wrong about VPN users. Headquarters matching is wrong about defense affiliation. The fix is never a bigger keyword list.

How to Use Company Info API

If you want to reproduce the lookup, the endpoint is GET /lookup?domain=example.com. You will need a RapidAPI key.

curl example:

curl --request GET \
  --url 'https://company-info1.p.rapidapi.com/lookup?domain=github.com' \
  --header 'X-RapidAPI-Host: company-info1.p.rapidapi.com' \
  --header 'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY'
Enter fullscreen mode Exit fullscreen mode

Python example:

import requests

url = "https://company-info1.p.rapidapi.com/lookup"
headers = {
    "X-RapidAPI-Host": "company-info1.p.rapidapi.com",
    "X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY"
}
params = {"domain": "github.com"}

r = requests.get(url, headers=headers, params=params, timeout=20)
print(r.json())
Enter fullscreen mode Exit fullscreen mode

The docs and subscription page are at https://rapidapi.com/On13uka/api/company-info1. The repository with notes and issue tracking is at https://github.com/On13uka/company-info-api.

The endpoint gives you a company profile pulled from Wikipedia, Wikidata, SEC EDGAR, GitHub, and UK Companies House. It returns a health_score, a github_org fingerprint, CEO and founder names, and the parent_company field that caused me so much grief. Use it for enrichment. Do not use it for guilt.

The Unanswered Question

I ended the job with 39,847 flagged records and no clean way to unflag them. The classifier is still running in staging, and the sales team is still asking why their dashboard has a "defense" column. I have not decided whether to delete the column or rebuild it with a human-in-the-loop review.

The scariest part is not the 40,000 flags. It is the records I did not flag. A pipeline that confidently labels GitHub as a defense contractor while missing a quiet RF contractor is not a pipeline you should trust for anything important.

What is the worst false-positive company tag you have ever shipped to production?

Top comments (0)