daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

companies-and-finance.md (36742B)


      1 ---
      2 title: "Companies, Ownership & Finance"
      3 description: "Corporate registries, filings and beneficial-ownership data for working out who actually controls a company."
      4 category: osint
      5 subcategory: "Corporate & Financial"
      6 tags: [osint, companies, finance, ownership, filings]
      7 tools: [opencorporates, edgar, edgartools, aleph, companies-house, opensanctions, icij-offshore-leaks]
      8 difficulty: intermediate
      9 updated: 2026-10-03
     10 references:
     11   - name: "Bellingcat's Online Investigation Toolkit"
     12     url: "https://bellingcat.gitbook.io/toolkit"
     13     author: "Bellingcat"
     14     license: none
     15     relation: derived
     16     note: "Tool catalogue: names, descriptions, cost flags and links for this area."
     17   - name: "OSINT Newsletter Tools Library"
     18     url: "https://tools.osintnewsletter.com"
     19     author: "The OSINT Newsletter"
     20     license: none
     21     relation: derived
     22     note: "Second tool catalogue, cross-checked against the above."
     23 ---
     24 
     25 ## What this covers
     26 
     27 Establishing what a company is, who owns it, and what it has told regulators. The pattern that
     28 matters: the registry tells you the *legal* structure, and the legal structure is often designed to
     29 obscure who benefits. Getting to the human at the end takes several sources in a particular order.
     30 
     31 ## Method
     32 
     33 1. **Start at the national registry**, which is authoritative. Aggregators are convenient but
     34    stale, and for anything you will publish the registry page is the citation.
     35 2. **Get the registration number** and use it thereafter. Company names are reused across
     36    jurisdictions, reused within them after dissolution, and changed deliberately.
     37 3. **Pull the filings, not the summary.** Annual accounts, director appointments and charges carry
     38    addresses, signatures, auditors and related parties that the summary page omits. The scanned PDF
     39    often has a signature and a handwritten date the structured data does not.
     40 4. **Follow officers sideways.** One director's other appointments frequently reveal the group the
     41    company actually belongs to — and distinguish a decision-maker from a nominee, because a
     42    nominee has dozens or hundreds.
     43 5. **Screen the names you have** against sanctions and politically-exposed-person data before you
     44    go further. A hit changes what the rest of the chain means, and it is cheap to check.
     45 6. **Cross-border means repeating the whole process** in each jurisdiction, and each one publishes
     46    something different: the UK publishes officers and PSCs free, Delaware publishes almost nothing,
     47    the EU publishes through BRIS with per-country gaps, and secrecy jurisdictions publish the
     48    existence of the company and nothing else. A chain terminating in one of them is the normal
     49    outcome, not a failure.
     50 7. **Check leak archives where the chain goes dark.** OCCRP Aleph and ICIJ Offshore Leaks hold what
     51    registries do not, with the caveat that leaked data is a snapshot of one moment.
     52 8. **Write down what each jurisdiction refused to tell you.** "Beneficial owner not published in
     53    this jurisdiction" is a finding about the structure, and it is the sentence that makes the
     54    analysis defensible rather than incomplete.
     55 
     56 ## Core sources
     57 
     58 | Source | Coverage |
     59 | --- | --- |
     60 | [OpenCorporates](https://opencorporates.com/) | The largest open company database, ~200 jurisdictions. Best starting point for "does this company exist and where". |
     61 | [Companies House](https://find-and-update.company-information.service.gov.uk/) | UK and Gibraltar. Free, complete filing history including scanned documents, and a clean API. The best-documented major registry. |
     62 | [SEC EDGAR](https://www.sec.gov/edgar/search/) | All US public-company filings. Full-text searchable back to 2001 and genuinely free. |
     63 | [OCCRP Aleph](https://aleph.occrp.org/) | Registries, leaks and court records in one index, with a shared entity model. The tool for cross-border work. |
     64 | [OpenSanctions](https://www.opensanctions.org/) | Consolidated sanctions lists, PEP data and persons of interest, as bulk data and an API. |
     65 | [ICIJ Offshore Leaks](https://offshoreleaks.icij.org/) | Panama / Paradise / Pandora Papers entities, officers and intermediaries. |
     66 | [Open Ownership](https://register.openownership.org/) | Beneficial-ownership data, where it is published at all. |
     67 | [BRIS](https://e-justice.europa.eu/content_find_a_company-489-en.do) | Consolidated search across most EU, Iceland, Liechtenstein and Norway registers. |
     68 
     69 ## Key tools
     70 
     71 ### Companies House API
     72 
     73 The reference implementation of what a company registry ought to be: free, keyed, documented,
     74 and complete back to incorporation including the scanned paper filings. Use it as the model for how
     75 much you should expect elsewhere, and be disappointed accordingly.
     76 
     77 Register at
     78 [developer.company-information.service.gov.uk](https://developer.company-information.service.gov.uk/)
     79 for a free key. Authentication is HTTP basic with the key as the username and an empty password —
     80 note the trailing colon.
     81 
     82 ```bash
     83 export CH_KEY='your-key-here'
     84 ```
     85 
     86 ```bash
     87 # find the company and get its number, which is what everything else keys on
     88 curl -s -u "$CH_KEY:" \
     89   'https://api.company-information.service.gov.uk/search/companies?q=example+trading+ltd' \
     90   | jq '.items[] | {title, company_number, company_status, address_snippet}'
     91 
     92 # the profile: incorporation date, SIC codes, registered office, accounts due
     93 curl -s -u "$CH_KEY:" \
     94   'https://api.company-information.service.gov.uk/company/12345678' \
     95   | jq '{company_name, date_of_creation, company_status, sic_codes, registered_office_address}'
     96 
     97 # officers, including resignation dates — the sideways pivot starts here
     98 curl -s -u "$CH_KEY:" \
     99   'https://api.company-information.service.gov.uk/company/12345678/officers' \
    100   | jq '.items[] | {name, officer_role, appointed_on, resigned_on, links}'
    101 
    102 # persons with significant control: the UK's beneficial-ownership disclosure
    103 curl -s -u "$CH_KEY:" \
    104   'https://api.company-information.service.gov.uk/company/12345678/persons-with-significant-control' \
    105   | jq '.items[] | {name, kind, natures_of_control, notified_on, ceased_on}'
    106 
    107 # every other appointment this officer holds — nominee detection in one call
    108 curl -s -u "$CH_KEY:" \
    109   'https://api.company-information.service.gov.uk/officers/OFFICER_ID/appointments' \
    110   | jq '{total:.total_results, items:[.items[] | .appointed_to.company_name]}'
    111 
    112 # charges and mortgages, which name lenders the company never advertised
    113 curl -s -u "$CH_KEY:" \
    114   'https://api.company-information.service.gov.uk/company/12345678/charges' \
    115   | jq '.items[] | {created_on, status, persons_entitled}'
    116 
    117 # the filing history, then fetch the scanned document itself
    118 curl -s -u "$CH_KEY:" \
    119   'https://api.company-information.service.gov.uk/company/12345678/filing-history' \
    120   | jq '.items[] | {date, type, description, doc:.links.document_metadata}'
    121 
    122 # search officers by name across all UK companies
    123 curl -s -u "$CH_KEY:" \
    124   'https://api.company-information.service.gov.uk/search/officers?q=jane+smith' \
    125   | jq '.items[] | {title, appointment_count, date_of_birth}'
    126 ```
    127 
    128 Rate limit is 600 requests per five minutes per key; exceed it and you get HTTP 429 with a
    129 `Retry-After`. The document-download host is `document-api.company-information.service.gov.uk`, not
    130 the API host, and it needs the same basic auth plus an `Accept: application/pdf` header.
    131 
    132 What it does not tell you: a PSC statement is self-declared and unverified, the 25% threshold means
    133 real control can sit legally just underneath disclosure, and `date_of_birth` is published as month
    134 and year only. "PSC: none" sometimes means genuinely dispersed ownership and sometimes means nobody
    135 filed.
    136 
    137 ### OpenCorporates
    138 
    139 The aggregator that normalises ~200 jurisdictions into one schema, which is what makes it the right
    140 first call when you do not yet know where a company is registered. Its value is breadth and
    141 cross-jurisdiction name matching; its weakness is freshness, so confirm anything important against
    142 the registry it came from.
    143 
    144 **The API is key-gated and mostly paid.** Free keys exist for open-data projects that republish
    145 under a share-alike licence, and journalists, academics and NGOs can apply for free or discounted
    146 access, but the free allowance is small — of the order of 50 requests a day. Commercial plans start
    147 in the low thousands of pounds a year. Without a key the API returns HTTP 401; the website search
    148 remains free.
    149 
    150 ```bash
    151 export OC_TOKEN='your-api-token'
    152 ```
    153 
    154 ```bash
    155 # name search across every jurisdiction OpenCorporates holds
    156 curl -s -G 'https://api.opencorporates.com/v0.4/companies/search' \
    157   --data-urlencode 'q=example trading' --data-urlencode "api_token=$OC_TOKEN" \
    158   | jq '.results.companies[].company | {name, jurisdiction_code, company_number, current_status}'
    159 
    160 # narrow to one jurisdiction once you know it
    161 curl -s -G 'https://api.opencorporates.com/v0.4/companies/search' \
    162   --data-urlencode 'q=example trading' --data-urlencode 'jurisdiction_code=gb' \
    163   --data-urlencode "api_token=$OC_TOKEN" | jq '.results.total_count'
    164 
    165 # the canonical record, including the source URL you should cite instead
    166 curl -s -G 'https://api.opencorporates.com/v0.4/companies/gb/12345678' \
    167   --data-urlencode "api_token=$OC_TOKEN" \
    168   | jq '.results.company | {name, incorporation_date, registered_address_in_full, source}'
    169 
    170 # officers attached to that company
    171 curl -s -G 'https://api.opencorporates.com/v0.4/companies/gb/12345678' \
    172   --data-urlencode "api_token=$OC_TOKEN" \
    173   | jq '.results.company.officers[].officer | {name, position, start_date, end_date}'
    174 
    175 # search officers by name globally — the cross-border nominee sweep
    176 curl -s -G 'https://api.opencorporates.com/v0.4/officers/search' \
    177   --data-urlencode 'q=jane smith' --data-urlencode "api_token=$OC_TOKEN" \
    178   | jq '.results.officers[].officer | {name, jurisdiction_code, company:.company.name}'
    179 
    180 # every company at one address, which is how you find a formation agent
    181 curl -s -G 'https://api.opencorporates.com/v0.4/companies/search' \
    182   --data-urlencode 'q=' --data-urlencode 'registered_address=*Tortola*' \
    183   --data-urlencode "api_token=$OC_TOKEN" | jq '.results.total_count'
    184 
    185 # check your remaining allowance before a loop burns the day's quota
    186 curl -s -G 'https://api.opencorporates.com/v0.4/account_status' \
    187   --data-urlencode "api_token=$OC_TOKEN" | jq '.results.account_status.usage'
    188 ```
    189 
    190 Every company record carries a `source` object with the registry URL and the date OpenCorporates
    191 scraped it. That date is the one thing you must read: a record last refreshed two years ago will
    192 show a director who resigned eighteen months back as current.
    193 
    194 ### SEC EDGAR full-text search
    195 
    196 Every US filing since 2001, searchable by phrase. This is the one free full-text corporate archive
    197 of real size, and it is the fastest way to find a private person or entity named in someone else's
    198 filing — a subsidiary list, a related-party note, a beneficial-ownership schedule.
    199 
    200 There is no API key. The identification mechanism is the `User-Agent` header, which must name your
    201 application and a contact address; send a generic one and you get HTTP 403 and a short IP block.
    202 The limit is ten requests per second across all `sec.gov` hosts.
    203 
    204 ```bash
    205 UA='DAEMON-SEC research you@example.com'
    206 ```
    207 
    208 ```bash
    209 # phrase search across all filings — quotes force an exact phrase
    210 curl -s -A "$UA" -G 'https://efts.sec.gov/LATEST/search-index' \
    211   --data-urlencode 'q="Example Trading Limited"' \
    212   | jq '{total:.hits.total.value, hits:[.hits.hits[] | {name:._source.display_names, date:._source.file_date, id:._id}]}'
    213 
    214 # restrict to a form type: beneficial-ownership schedules
    215 curl -s -A "$UA" -G 'https://efts.sec.gov/LATEST/search-index' \
    216   --data-urlencode 'q="Example Trading"' --data-urlencode 'forms=SC 13D' \
    217   | jq '.hits.total.value'
    218 
    219 # restrict to a date window — dateRange=custom is required alongside the dates
    220 curl -s -A "$UA" -G 'https://efts.sec.gov/LATEST/search-index' \
    221   --data-urlencode 'q="going concern"' --data-urlencode 'forms=10-K' \
    222   --data-urlencode 'dateRange=custom' \
    223   --data-urlencode 'startdt=2025-01-01' --data-urlencode 'enddt=2025-06-30' \
    224   | jq '.hits.total.value'
    225 
    226 # everything one filer said about a term, by CIK
    227 curl -s -A "$UA" -G 'https://efts.sec.gov/LATEST/search-index' \
    228   --data-urlencode 'q="related party"' --data-urlencode 'entityName=0000320193' \
    229   | jq '.hits.total.value'
    230 
    231 # page past the first ten results (the corpus caps at 10,000 total)
    232 curl -s -A "$UA" -G 'https://efts.sec.gov/LATEST/search-index' \
    233   --data-urlencode 'q="Example Trading"' --data-urlencode 'from=10' \
    234   | jq '[.hits.hits[]._id]'
    235 
    236 # a filer's complete submission index, from the structured-data host
    237 curl -s -A "$UA" 'https://data.sec.gov/submissions/CIK0000320193.json' \
    238   | jq '{name, cik, formerNames, tickers, recent:[.filings.recent.form[0:5]]}'
    239 
    240 # resolve a ticker to a CIK, which every other endpoint wants zero-padded
    241 curl -s -A "$UA" 'https://www.sec.gov/files/company_tickers.json' \
    242   | jq -r 'to_entries[] | select(.value.ticker=="AAPL") | .value.cik_str'
    243 
    244 # one XBRL concept across a company's whole history
    245 curl -s -A "$UA" \
    246   'https://data.sec.gov/api/xbrl/companyconcept/CIK0000320193/us-gaap/Revenues.json' \
    247   | jq '.units["USD"] | length'
    248 ```
    249 
    250 The `_id` in a hit is `accession-number:filename`, which reconstructs to a document URL under
    251 `https://www.sec.gov/Archives/edgar/data/<cik>/<accession-no-dashes>/<filename>`. The result set is
    252 capped at 10,000 and paged ten at a time, so a broad query needs narrowing by form and date rather
    253 than paging.
    254 
    255 Full-text coverage starts in 2001. Anything older is in EDGAR but only findable by filer and form,
    256 not by phrase — which matters when the structure you are chasing was set up in the 1990s.
    257 
    258 ### edgartools
    259 
    260 A Python layer over EDGAR that parses filings into typed objects rather than handing you HTML, and
    261 handles the `User-Agent` requirement and rate limiting for you. Use it the moment you need more
    262 than a handful of filings, and particularly for Form 4 insider transactions and 13F holdings, where
    263 the raw XML is tedious and the parsing is where the mistakes happen.
    264 
    265 ```bash
    266 pip install edgartools
    267 ```
    268 
    269 ```python
    270 from edgar import Company, set_identity, get_filings
    271 
    272 set_identity("you@example.com")      # required; this becomes the User-Agent
    273 
    274 c = Company("AAPL")
    275 
    276 # the filing index for one form type
    277 c.get_filings(form="10-K").head(5)
    278 
    279 # insider transactions as structured objects, not XML
    280 c.get_filings(form="4").latest().obj()
    281 
    282 # institutional holdings from a 13F, already parsed into positions
    283 get_filings(form="13F-HR").latest().obj().holdings
    284 
    285 # subsidiary and related-party text out of the latest annual report
    286 tenk = c.get_filings(form="10-K").latest().obj()
    287 print(tenk["Item 1"][:2000])
    288 
    289 # one XBRL concept as a DataFrame, for a time series
    290 c.get_facts().query().by_concept("Revenues").to_dataframe()
    291 
    292 # filings across all companies in a quarter, to sweep a form type
    293 get_filings(year=2025, quarter=1, form="SC 13D")
    294 ```
    295 
    296 `set_identity` is not optional — without it the library refuses to call EDGAR, which is the correct
    297 behaviour. For bulk retrieval of raw documents rather than parsed objects,
    298 `sec-edgar-downloader` is the simpler tool: `Downloader("YourOrg", "you@example.com")` then
    299 `dl.get("10-K", "AAPL", after="2020-01-01", limit=5)`.
    300 
    301 ### OpenSanctions
    302 
    303 Consolidated sanctions designations, politically-exposed-person lists and persons of interest from
    304 several hundred sources, normalised into one entity model. Run every name you extract from a
    305 registry through it, because a designation changes the legal meaning of the whole structure.
    306 
    307 The API is metered pay-as-you-go, with **free keys available on request for journalism,
    308 civil-society and academic work**. The full dataset is also published for download under a
    309 share-alike licence, and the matching service is open source as
    310 [yente](https://github.com/opensanctions/yente), which you can self-host with no key at all — the
    311 right choice when the names you are screening should not leave your machine.
    312 
    313 ```bash
    314 export OS_API_KEY='your-key'
    315 ```
    316 
    317 ```bash
    318 # free-text search across the default collection
    319 curl -s -H "Authorization: ApiKey $OS_API_KEY" -G \
    320   'https://api.opensanctions.org/search/default' --data-urlencode 'q=Ilham Aliyev' \
    321   | jq '.results[] | {id, caption, schema, datasets, topics}'
    322 
    323 # restrict to companies rather than people
    324 curl -s -H "Authorization: ApiKey $OS_API_KEY" -G \
    325   'https://api.opensanctions.org/search/default' \
    326   --data-urlencode 'q=Example Trading' --data-urlencode 'schema=Company' \
    327   | jq '.total.value'
    328 
    329 # structured matching, which scores candidates instead of string-matching
    330 curl -s -H "Authorization: ApiKey $OS_API_KEY" -X POST \
    331   -H 'Content-Type: application/json' \
    332   'https://api.opensanctions.org/match/default' \
    333   -d '{"queries":{"q1":{"schema":"Person","properties":{"name":["Jane Smith"],"birthDate":["1970"],"nationality":["gb"]}}}}' \
    334   | jq '.responses.q1.results[] | {score, caption, topics}'
    335 
    336 # the full entity, including every alias, address and linked entity
    337 curl -s -H "Authorization: ApiKey $OS_API_KEY" \
    338   'https://api.opensanctions.org/entities/NK-ENTITY-ID' | jq '.properties'
    339 
    340 # what datasets a hit came from, which is how you cite the designation
    341 curl -s -H "Authorization: ApiKey $OS_API_KEY" \
    342   'https://api.opensanctions.org/datasets' | jq '.datasets[] | {name, title, entity_count}'
    343 
    344 # self-hosted yente takes the same paths with no key
    345 curl -s -G 'http://localhost:8000/search/default' --data-urlencode 'q=Jane Smith' | jq '.total'
    346 ```
    347 
    348 A match is a match on *data*, not an identification. Common names produce confident-looking hits on
    349 unrelated people, and the sanctions lists themselves contain transliteration variants of one person
    350 as separate entries. Always open the entity, read the aliases and birth date, and cite the
    351 underlying designation — the OFAC or EU legal act — not the aggregator.
    352 
    353 ### OCCRP Aleph
    354 
    355 Registries, leaks, court records, procurement data and gazettes in one index, all mapped onto the
    356 FollowTheMoney entity schema. That shared schema is the point: a `Company` from a Latvian registry
    357 and a `Company` from a leaked corporate database have the same property names, so you can ask one
    358 query across both.
    359 
    360 API keys come with an Aleph account; some collections need separate permission and investigative
    361 collections are not public. The header format is `Authorization: ApiKey <key>`, and all paths sit
    362 under `/api/2/`.
    363 
    364 ```bash
    365 export ALEPH_KEY='your-api-key'
    366 H="Authorization: ApiKey $ALEPH_KEY"
    367 ```
    368 
    369 ```bash
    370 # free-text search across every collection you can see
    371 curl -s -H "$H" -G 'https://aleph.occrp.org/api/2/entities' \
    372   --data-urlencode 'q=Example Trading Limited' \
    373   | jq '.results[] | {id, schema, caption, collection:.collection.label}'
    374 
    375 # restrict by entity type — the schema names are the FollowTheMoney ones
    376 curl -s -H "$H" -G 'https://aleph.occrp.org/api/2/entities' \
    377   --data-urlencode 'q=Jane Smith' --data-urlencode 'filter:schema=Person' \
    378   | jq '.total'
    379 
    380 # restrict to one collection, once you know which dataset matters
    381 curl -s -H "$H" -G 'https://aleph.occrp.org/api/2/entities' \
    382   --data-urlencode 'q=Example Trading' --data-urlencode 'filter:collection_id=123' \
    383   | jq '.total'
    384 
    385 # one entity in full, with every property the schema allows
    386 curl -s -H "$H" 'https://aleph.occrp.org/api/2/entities/ENTITY_ID' | jq '.properties'
    387 
    388 # what this entity is connected to and how — ownership, directorship, payment
    389 curl -s -H "$H" -G 'https://aleph.occrp.org/api/2/entities/ENTITY_ID/expand' \
    390   --data-urlencode 'limit=50' \
    391   | jq '.results[] | {property, count, entities:[.entities[].caption]}'
    392 
    393 # the entity-model definitions, so you know which properties exist to filter on
    394 curl -s 'https://aleph.occrp.org/api/2/metadata' \
    395   | jq '.schemata | keys | map(select(. | test("Company|Ownership|Person|Directorship")))'
    396 
    397 # list the collections your key can reach, with their ids and update dates
    398 curl -s -H "$H" -G 'https://aleph.occrp.org/api/2/collections' --data-urlencode 'limit=50' \
    399   | jq '.results[] | {id, label, category, updated_at}'
    400 ```
    401 
    402 The schema is what makes Aleph worth the learning curve. `Company` and `Person` are the nodes;
    403 `Ownership`, `Directorship`, `Membership` and `Payment` are *intermediate entities* with their own
    404 properties — an `Ownership` carries a percentage, a start date and an end date, and connects an
    405 owner to an asset. `/expand` walks those edges, which is how you traverse a chain without reading
    406 every document.
    407 
    408 Leaked collections are snapshots. An `Ownership` from a 2016 leak describes 2016, and saying so is
    409 the difference between a finding and a libel risk.
    410 
    411 ### ICIJ Offshore Leaks
    412 
    413 Entities, officers, intermediaries and addresses from the Panama, Paradise, Pandora, Bahamas and
    414 Offshore Leaks investigations. Web-only, no API, and worth a walkthrough because the structure of
    415 the database is not obvious from the search box.
    416 
    417 Search at [offshoreleaks.icij.org](https://offshoreleaks.icij.org/) by company name, person name or
    418 address. Read the result in this order.
    419 
    420 ```text
    421 Entity        the offshore company itself: jurisdiction, incorporation and inactivation
    422               dates, and the leak it came from. The jurisdiction plus the dates is what
    423               you take back to that jurisdiction's registry
    424 Officers      the people and companies attached, each with a role (shareholder, director,
    425               beneficiary, nominee). "Nominee" here is explicit, which is rarer than it
    426               sounds
    427 Intermediary  the law firm or agent that formed it. This is the strongest pivot in the
    428               database — the intermediary's other clients are listed, and a pattern of
    429               one agent forming a cluster of companies is a structure
    430 Addresses     search by address, not name, when a name is too common. A residential
    431               address shared by forty companies is the finding
    432 Linked        the graph view, which shows the chain between two entities if one exists
    433 ```
    434 
    435 Capture the node URL for every entity and officer, the leak name, and the date range the data
    436 covers. The URLs are stable and citable.
    437 
    438 Two limits to state every time you use it: being in the database is not evidence of wrongdoing —
    439 offshore structures are legal and ICIJ says so prominently — and the data is as of the leak, which
    440 for Panama means 2015. A company shown as active was active then.
    441 
    442 ### Jurisdiction-by-jurisdiction fallbacks
    443 
    444 When the chain crosses a border, what you can get changes completely. These are the sources worth
    445 knowing before you conclude a jurisdiction publishes nothing.
    446 
    447 | Source | What it adds |
    448 | --- | --- |
    449 | [BRIS / e-Justice](https://e-justice.europa.eu/content_find_a_company-489-en.do) | One search box over most EU registers. Coverage per country varies from full filings to name-and-number only. |
    450 | [North Data](https://northdata.com) | EU registers with relationship graphs and German trade-register notices, which often name shareholders the registry does not. |
    451 | [Open Ownership Register](https://register.openownership.org/) | Beneficial-ownership declarations consolidated across the countries that publish them. |
    452 | [RuPEP](https://rupep.org/en/) | Politically exposed persons in Russia, Belarus, Kazakhstan, Kyrgyzstan, Georgia and Moldova, with family and associate links. |
    453 | [SanctionsExplorer](https://sanctionsexplorer.org/) | Historical OFAC, UN and EU designations, including delisted ones — which is what you need for a structure that predates a current list. |
    454 | [ImportYeti](https://www.importyeti.com/) | US customs sea-shipment records: who ships to whom, which evidences a trading relationship no registry records. |
    455 | [Wikipedia's register list](https://en.wikipedia.org/wiki/List_of_official_business_registers) | The maintained index of official registers worldwide. Start here for a jurisdiction you have not worked before. |
    456 
    457 ## Reading the structure
    458 
    459 - **Nominee directors** appear on dozens or hundreds of companies. A director with 200 appointments
    460   is a service provider, not a decision-maker, and the Companies House appointments endpoint tells
    461   you which you have in one call.
    462 - **Registered-address clustering** usually means a formation agent. Search the address, not the
    463   name, and the agent's whole book appears.
    464 - **Shareholders that are themselves companies** are the chain you have to walk. Keep going until
    465   you hit a natural person or a jurisdiction that will not tell you, then record which.
    466 - **Charges and mortgages** name lenders, which reveals banking relationships the company did not
    467   advertise and gives you a regulated counterparty who had to do their own due diligence.
    468 - **Dates are the load-bearing part.** An ownership that ended before the event you are
    469   investigating is not relevant, and a leak snapshot has one date for everything in it.
    470 
    471 ## Tool reference
    472 
    473 | Tool | What it does | Cost |
    474 | --- | --- | --- |
    475 | [527 Explorer](https://projects.propublica.org/527-explorer/) | ProPublica's 527 Explorer is a database that allows users to examine the finances of organizations known as 527s in the United States, which can raise… | free |
    476 | [BlockExplorer](https://blockexplorer.com/) | Following a bitcoin trail or following a bitcoin account? | free |
    477 | [Companies House](https://find-and-update.company-information.service.gov.uk/) | Search companies and individuals in the United Kingdom and Gibraltar. | free |
    478 | [EDGAR Command Line Interface (edgar-tool)](https://pypi.org/project/edgar-tool/) | Tool for the retrieval of corporate and financial data from SEC's EDGAR (Electronic Data Gathering, Analysis, and Retrieval) database. | free |
    479 | [EDGAR](https://www.sec.gov/edgar/search/) | Database of corporate filings for the US | free |
    480 | [Etherscan](https://etherscan.io/) | An explorer that allows researchers to track wallets, transactions and more on the Ethereum blockchain. | free |
    481 | [EU consolidated corporate registers (BRIS)](https://e-justice.europa.eu/content_find_a_company-489-en.do) | Consolidated company registers covering most of the EU, Iceland, Liechtenstein and Norway. | free |
    482 | [EU Sanctions Map](https://www.sanctionsmap.eu/) | Database of sanctions imposed by the European Union and the United Nations | free |
    483 | [Global Suppliers Online](https://www.globalsuppliersonline.com/) | A site dedicated to connect suppliers and buyers of goods from all over the world. | partly free |
    484 | [ICIJ Offshore Leaks Database](http://offshoreleaks.icij.org/) | Find out who’s behind more than 810k offshore companies, foundations and trusts from the Panama Papers, the Offshore Leaks, the Bahamas Leaks and the… | free |
    485 | [ImportGenius](https://www.importgenius.com/) | Commercial supplier of trade data for 23 countries. Paid service but journalists can ask for free access. | paid |
    486 | [ImportYeti](https://www.importyeti.com/) | Search 60 million US customs sea shipment records, find company suppliers. | free |
    487 | [LittleSis](https://littlesis.org/database) | Connects the dots between influential / wealthy individuals in (mostly US) politics and business. | free |
    488 | [Lumen](https://lumendatabase.org/) | A research project collecting and publishing legal takedown notices for online content transparency | free |
    489 | [North Data](https://northdata.com) | Search for people and companies in EU corporate and trade registers + visualize relationships | partly free |
    490 | [OpenSecrets](https://www.opensecrets.org/) | Data on campaign finance, lobbying, and spending in U.S. politics | free |
    491 | [OSINT Tools Map](https://cybdetective.com/osintmap/) | An interactive map serving as a curated archive of country-specific OSINT resources, including business registries, court records, and cadastral maps… | free |
    492 | [RuPEP](https://rupep.org/en/) | Online database of politically exposed persons in Russia, Belarus, Kyrgyzstan, Kazakhstan, Georgia and Moldova. | free |
    493 | [SanctionsExplorer](https://sanctionsexplorer.org/) | A comprehensive database of current and historical OFAC/UN/EU sanctions | free |
    494 | [UN Comtrade Database](https://comtradeplus.un.org/) | United Nations free database of global trade. | free |
    495 | [Wikipedia list of company registers](https://en.wikipedia.org/wiki/List_of_official_business_registers) | A list of official business registers around the world. | free |
    496 | China-related resources | Resources for research on companies in China. | — |
    497 | OpenSanctions | Open-source international database of sanctions data, persons of interest and politically exposed persons. | partly free |
    498 
    499 ## Pitfalls
    500 
    501 - **Registry data is self-reported** and frequently not verified by anyone. A filed address may be
    502   fictional.
    503 - **"Beneficial owner" is defined differently everywhere**, and thresholds (often 25%) let real
    504   control sit just underneath the disclosure line.
    505 - **Aggregators lag.** For anything current, go to the registry itself.
    506 - **Name collisions across jurisdictions** are constant. Always carry the registration number.
    507 - **Dissolved does not mean gone.** Historical filings often hold what you need, and some registries
    508   purge them after a few years — capture early.
    509 
    510 ## Worked example
    511 
    512 One datum: the name "Northgate Minerals Trading" on an invoice. The company, the numbers and the
    513 returns are invented; the order of the pivots and what each source can and cannot settle are not.
    514 
    515 ```bash
    516 # 1. where does it exist at all
    517 curl -s -G 'https://api.opencorporates.com/v0.4/companies/search' \
    518   --data-urlencode 'q=Northgate Minerals Trading' --data-urlencode "api_token=$OC_TOKEN" \
    519   | jq '.results.companies[].company | {name, jurisdiction_code, company_number, current_status}'
    520 # two hits: gb/09876543 (active) and vg/1654321 (OpenCorporates record, source dated 2019)
    521 ```
    522 
    523 A UK company and a British Virgin Islands company with the same name. The UK one is where the data
    524 is, so start there and carry the number `09876543`.
    525 
    526 ```bash
    527 # 2. who is declared to control it
    528 curl -s -u "$CH_KEY:" \
    529   'https://api.company-information.service.gov.uk/company/09876543/persons-with-significant-control' \
    530   | jq '.items[] | {name, kind, natures_of_control}'
    531 # one PSC, kind "corporate-entity-person-with-significant-control",
    532 # name "Northgate Holdings Ltd", country of registration "Virgin Islands, British"
    533 ```
    534 
    535 The declared controller is the BVI company, so UK disclosure has handed the chain straight back
    536 offshore. That is the expected outcome, and worth stating as one.
    537 
    538 ```bash
    539 # 3. the officers, and whether they are real or nominal
    540 curl -s -u "$CH_KEY:" \
    541   'https://api.company-information.service.gov.uk/company/09876543/officers' \
    542   | jq '.items[] | {name, officer_role, appointed_on, id:.links.officer.appointments}'
    543 # two directors; take each appointments link
    544 curl -s -u "$CH_KEY:" \
    545   'https://api.company-information.service.gov.uk/officers/AbC123.../appointments' | jq '.total_results'
    546 # 147
    547 ```
    548 
    549 147 appointments makes that director a formation-agent nominee, not a decision-maker. The other has
    550 three, all in the same group — that is the person to follow.
    551 
    552 ```bash
    553 # 4. screen both names and the BVI entity
    554 curl -s -H "Authorization: ApiKey $OS_API_KEY" -G \
    555   'https://api.opensanctions.org/search/default' --data-urlencode 'q=Northgate Holdings' \
    556   | jq '.results[] | {caption, schema, topics, datasets}'
    557 # no designation; one PEP-adjacent hit on a similarly-named Cyprus entity — not the same company
    558 ```
    559 
    560 A near-miss on a different entity is exactly the false positive to discard explicitly, in writing,
    561 so it does not resurface later as a claim.
    562 
    563 ```bash
    564 # 5. the offshore end, where the registry publishes nothing
    565 curl -s -H "Authorization: ApiKey $ALEPH_KEY" -G 'https://aleph.occrp.org/api/2/entities' \
    566   --data-urlencode 'q=Northgate Holdings' --data-urlencode 'filter:schema=Company' \
    567   | jq '.results[] | {id, caption, collection:.collection.label}'
    568 # a hit in an ICIJ collection; expand it for the ownership edges
    569 curl -s -H "Authorization: ApiKey $ALEPH_KEY" -G \
    570   'https://aleph.occrp.org/api/2/entities/ENTITY_ID/expand' --data-urlencode 'limit=50' \
    571   | jq '.results[] | {property, entities:[.entities[].caption]}'
    572 # Ownership -> a named individual, percentage 100, startDate 2014
    573 ```
    574 
    575 Cross-checking that individual in [ICIJ Offshore Leaks](https://offshoreleaks.icij.org/) gives the
    576 same person as beneficiary via the same BVI intermediary, with a residential address shared by
    577 eleven other companies — a second, independent confirmation of the same edge.
    578 
    579 ```bash
    580 # 6. does the name appear in anyone's US filings
    581 curl -s -A "$UA" -G 'https://efts.sec.gov/LATEST/search-index' \
    582   --data-urlencode 'q="Northgate Minerals Trading"' \
    583   | jq '.hits.hits[] | {name:._source.display_names, date:._source.file_date}'
    584 # one 10-K exhibit, 2023, listing it as a counterparty of a listed miner
    585 ```
    586 
    587 What you can assert: invoice name → UK company 09876543 (Companies House, retrieved with date) →
    588 corporate PSC in BVI (UK filing, self-declared) → named individual with 100% ownership from 2014
    589 (Aleph, ICIJ collection, snapshot date stated) → confirmed independently in the ICIJ public
    590 database via the same intermediary → named as a counterparty in a 2023 SEC exhibit. Six sources,
    591 two of them independent of each other on the key link.
    592 
    593 What you still cannot say: whether that individual controls it *today*. The ownership edge is from
    594 a leak snapshot, the BVI publishes nothing current, and the UK PSC declaration names the company
    595 rather than the person. "Beneficial ownership is not currently published in the British Virgin
    596 Islands; the most recent evidenced owner is X as of 2014" is the honest sentence, and it is a
    597 stronger finding than an unqualified assertion.
    598 
    599 What would falsify it: a later primary filing naming a different beneficial owner, the Aleph and
    600 ICIJ records resolving to different entities once registration numbers are compared, or the SEC
    601 exhibit referring to a namesake rather than company 09876543. The 2014 ownership edge is the
    602 oldest and weakest link; date it explicitly and replace it when a newer primary record appears.
    603 
    604 ## Broader catalogues
    605 
    606 - [Public Records OSINT](https://tools.osintnewsletter.com/tool-categories/public-records-osint)
    607 - [Blockchain/Cryptocurrency OSINT](https://tools.osintnewsletter.com/tool-categories/blockchain-and-cryptocurrency-osint)
    608 
    609 
    610 ## More tools
    611 
    612 Further tools for this area from the OSINT Newsletter Tools Library ([Blockchain/Cryptocurrency OSINT](https://tools.osintnewsletter.com/tool-categories/blockchain-and-cryptocurrency-osint)), excluding those already listed above.
    613 
    614 | Tool | What it does |
    615 | --- | --- |
    616 | [Arkham Intel](https://intel.arkm.com/) | A blockchain intelligence and analytics platform that de-anonymizes cryptocurrency transactions. |
    617 | [Bid Detail](https://www.biddetail.com/) | A procurement intelligence platform that makes government contract and tender data searchable. |
    618 | [Bitbo](https://bitbo.io/) | A Bitcoin data dashboard that tracks price, market, mining and on-chain metrics. |
    619 | [Bitcoin Talk](https://bitcointalk.org/) | A long-running online discussion forum focused on Bitcoin, cryptocurrencies, blockchain technology and related projects. |
    620 | [Bitcoin Whoswho](https://www.bitcoinwhoswho.com/) | Cryptocurrency intelligence tool used to investigate Bitcoin addresses and identify reported scams. |
    621 | [Block Explorer](https://www.blockexplorer.com/) | A blockchain search engine that lets you inspect cryptocurrency transactions, wallet addresses, blocks, and network activity. |
    622 | [Dune](https://dune.com/home) | A blockchain analytics platform that lets you explore and analyse data from cryptocurrencies and decentralised applications. |
    623 | [GuideStar](https://www.guidestar.org/) | A nonprofit intelligence platform that provides detailed information on registered charities and nonprofit organisations… |
    624 | [TheBigBrother](https://github.com/chadi0x/TheBigBrother) | All-in-one OSINT toolkit that helps track usernames across the web, investigate emails and domains, extract metadata, and follow… |
    625 
    626 ## Sources
    627 
    628 Both catalogues below are maintained by other people and are considerably larger than
    629 this page. Use them as the canonical index; this sheet is a working route through them.
    630 
    631 - [Bellingcat's Online Investigation Toolkit](https://bellingcat.gitbook.io/toolkit) — ~340 tools, each with its own
    632   review page covering cost, difficulty, requirements and limitations.
    633 - [OSINT Newsletter Tools Library](https://tools.osintnewsletter.com) — ~280 tools, organised by investigative goal.
    634 
    635 Neither publishes a licence, so nothing here is copied from them: tool names, one-line
    636 descriptions, cost flags and links are catalogue facts, and the method and commentary are
    637 this site's own. See [credits](/credits).