neobotnet / blog / company-of-the-week
company of the week·9 min read

company of the week: hubspot

HubSpot sells a customer-relationship and marketing platform — the CRM, email, landing pages and analytics that tens of thousands of companies run their marketing through. It runs a public bug bounty on HackerOne, which puts its public web surface in scope for outside research — neobotnet's full index is in /urls.

The scope is 7 root domains, and they hand back a company that isn't HubSpot. hubspot.com is 707 of 9,340 dns names — 7.6% of the estate. The other 92% is the multi-tenant machinery every customer runs through HubSpot: per-account email-sending hosts, customer landing pages, tenant sites. The in-scope estate is a public census of HubSpot's customers.

7
in-scope roots
9,340
dns names
39
live web servers
35,619
live email links
102,931
urls indexed

read from dns: the company is a directory of its customers

Public DNS hands you the shape of the company before a page loads. Here it hands you the customers, not the company:

hubspot  ·  7 in-scope roots  ·  9,340 dns names  ·  92% of them customers'
│
├─ hubspotemail.net ....... 5,885   per-account email sending
│     └─ hs-<portalid>.{f,s,t,cs}.hubspotemail.net · 3,880 hosts · 3,645 accounts
│        (remaining ~2,005 = opaque bounce / feedback-loop tokens)
│
├─ hubspotpagebuilder.com . 2,130   customer landing pages
│     └─ 2,020 brand-named tenants · 110 bare-numeric-id
│        craftech · curacel · highwayandheavyparts · pickettblackburn
│        atlasfiltri-1 · axisinstituto · paulzobercpa · mummyonabreak
│
├─ hubspot.com ............   707   the namesake — 7.6%
│     └─ 439 of 707 are <tenant>.sites.hubspot.com customer sites
│        justaddiceorchids · carpentercostin · odwlogistics · roberthalflegal
│        (~206 corporate/product hosts)
│
├─ hubspotpagebuilder.eu ..   368   customer landing pages (eu)
├─ hs-sites-eu1.com .......   218   customer sites (eu)
├─ hubapi.com .............    32   the api edge
└─ hs-sites.com ...........     0   apex in scope, 0 names enumerated · 16,646 urls

A portal id is HubSpot's per-account number — the identifier that names a customer inside the platform. On hubspotemail.net, 3,880 sending hosts are named hs-<portalid>.…, and they resolve to 3,645 distinct portal ids. That is 3,645 customer accounts, readable off DNS, before a page ever loads. On hubspotpagebuilder.com the tenants are named after the company itself — craftech, curacel, highwayandheavyparts — 2,020 brands hosting a landing page on HubSpot's default domain before they wire up a custom one. Even hubspot.com is majority tenant: 439 of its 707 names are <tenant>.sites.hubspot.com customer sites.

The org chart most companies leak in DNS is their own systems. HubSpot's DNS leaks its customers — brand names and account numbers, thousands of them, readable without loading a page. That is the shape of a multi-tenant platform seen from outside.

browse the dns layer in /dns →

the page-builder tenants →

read from http: 8,356 doors, one answer

8,800 hosts were probed, and 8,356 of them — 95% — answer the same thing: 403, forbidden. The multi-tenant edge returns "forbidden" to a bare hostname that carries no tenant routing. Only 39 answer 200, and they are almost all HubSpot's own front doors:

hubspot live surface  ·  8,800 probed  ·  8,356 answer 403  ·  39 answer 200
│
├─ the app, split by region   ("HubSpot | Redirecting...")
│     app-na1 · app-na2 · app-na3 · app-eu1 · app-ap1 · app.hubspot.com
│                              na1/na2/na3/eu1/ap1 = data-residency regions
│
├─ the front doors
│     login.hubspot.com ........ "HubSpot Login and Sign in"
│     mail.hubspot.com ......... "HubSpot - Corp - Sign In"
│     status.hubspot.com ....... "HubSpot Status"
│     ecosystem.hubspot.com .... "HubSpot Marketplace"
│     community.hubspot.com .... "HubSpot Community"
│     ir.hubspot.com ........... "Investor Relations | HubSpot"
│     unbound.hubspot.com ...... "UNBOUND 2026 | HubSpot's Annual Conference"
│
└─ the vendor stack hubspot itself runs
      trust.hubspot.com ....... "HubSpot Trust Center | Powered by Conveyor"
      preferences.hubspot.com . "Privacy Request Center | DataGrail"
      tools.hubapi.com ........ "Sign in ・ Cloudflare Access"

The app doesn't answer as one host; it answers as six. app-na1 through app-ap1 are data-residency regions — where a customer's data physically lives, na for North America, eu for Europe, ap for Asia-Pacific — and each region gets its own copy of the app front door, all returning HubSpot | Redirecting..., the login bounce.

The rest is the vendor stack HubSpot runs on itself, named in the titles: Conveyor fronts the trust center, DataGrail handles privacy requests, Atlassian serves the status page, and tools.hubapi.com sits behind Cloudflare Access — a login wall in front of internal tools. One oddity to walk back: redirect.hubspot.com answers with the title Google Public DNS — a redirect host pointed at Google's DNS docs, not a finding, just a curiosity.

see the 39 live front doors in /probes →

the 403 wall →

102,931 indexed URLs. By domain: hubspotemail.net holds 52,087 (35,619 at 200), hubspot.com 23,968 (13,407 at 200), hs-sites.com 16,646 (0 at 200 — every one a redirect to a customer's own custom domain), hubapi.com 3,297 (2,543 at 200). Ranked the way a researcher would work them.

1 — a recipient's email, in the link. neobotnet classifies every URL parameter against a signal taxonomy — a fixed list of shapes worth flagging. Across all 102,931 URLs the email signal fires on 139 URLs, and every one is a literal cleartext email address sitting in a query parameter. 133 of them answer 200. They are hubspotemail.net manage-preferences and unsubscribe links — /hs/manage-preferences/unsubscribe (67), /hs/manage-preferences/unsubscribe-all (61), /email-unsubscribe/email (5) — where the recipient's own address rides in the URL as the identifier.

Follow where that link goes. A URL with a cleartext email in it gets forwarded, archived in mailboxes, logged by every proxy and CDN it crosses, and handed as the Referer header to whatever the page loads. Whoever ends up holding it — an outside crawler, here — reads the address, and at 200 loads that person's subscription record with no login. Multiply by a platform that mints one such link per recipient per email, and the "who did which company email, and to whom" map is legible from outside. This is a signal, not a confirmed vulnerability — but it is live third-party data, so the right destination is HubSpot's HackerOne channel, not a blog post. neobotnet keeps the shape — the path, the parameter name, the count — and never the address.

see the email signal in /urls →

manage-preferences links carrying a recipient email, address column masked, in /urls

2 — the link is the identity, at scale. The 35,619 live links on hubspotemail.net are HubSpot's product turned inside out. 24,983 are manage-preferences / unsubscribe links; 8,672 are /e2t/tc/<token> click-tracking redirects — e2t is HubSpot's click tracker, and every link in every marketing email is rewritten to route through it; 1,334 are /email-unsubscribe/; 222 are hosted files. The tracking token identifies email, recipient and destination in one hop. The unsubscribe token (d=, _hsenc=) identifies the subscriber, _hsmi= is the message id, and utm_campaign= carries the campaign name in cleartext — shapes like utm_campaign=2024+Webinar+Invites. None of this is a leak in the bug sense; it is how the product works. But it means the marketing operations of thousands of companies are legible from outside: who mailed which campaign, to a subscriber addressable by link.

see the email-link machinery in /urls →

the email-link machinery on hubspotemail.net answering 200, in /urls

3 — customer documents, found by content-type. neobotnet filters by content_type — the label the server puts on the bytes — not by the file name in the path. That lens returns 208 PDFs, all at 200, served under /hubfs/<portalid>/…hubfs is HubSpot's file store, and the number after it is the customer's portal id — across 138 distinct customer accounts. The paths read like public marketing collateral: prospectuses, all-events calendars, ebooks, weekly FX reports, case studies, onboarding guides, ESG calendars. Here the methodology cuts the other way from usual: the file-extension lens returns more (857) than content-type (208), because 649 of those .pdf paths are dead links — so content-type is still the honest count, it just trims down this time instead of up. Mostly public by design; a few titles read internal — a "Final Notice" set, an "External" roundtable summary, a /gated/ asset reachable directly. Shape noted, not opened.

see the /hubfs documents in /urls →

The API, named and shut. On hubapi.com the named API namespaces are all present and all locked — crm, cms, marketing, automation, contacts, crm-objects each return 0 at 200. The only namespace answering 200 en masse is /events/ (2,521) — the telemetry beacon. The interesting surface is named and shut; the one that's open is tracking.

Now walk the loud alarms back — the discipline is the point. Across all 102,931 URLs the scary signals are nearly empty, and each is benign on inspection. 1 jwt: a previewJwt on hs-sites-eu1.com, status 403 — a CMS page-preview token, locked, not a session. 2 credential-in-url: an auth= signed one-time link token at 403, not a password. 7 cross-domain: HubSpot's own tracking script echoing the host page's own address (pageUrl, currentUrl, utm_referrer, canon) — not open redirects. 32 same-domain redirects: redirect_url, canon, loginRedirectUrl — login-return plumbing. And zero of each: auth tokens, cloud keys, path traversal, private IPs.

what it adds up to

Ranked for a researcher working the program:

  1. the cleartext-email unsubscribe links — 133 answering 200, the one live PII item; disclosure-channel first.
  2. the tenant census itself — 3,645 accounts and 2,020 brand-named tenants readable off DNS; the platform's customer list is public by construction.
  3. the email-link machinery — the campaign and subscriber surface, legible at scale.
  4. the /hubfs customer docs — mostly public, a few internal-reading; content-type is the lens.

Two things stated plainly, the way this series always closes. Every item above is a signal, not a confirmed vulnerability — neobotnet surfaces the shape; confirming exploitability is the researcher's job. And the right destination for anything live is HubSpot's HackerOne program, not a blog post.

next week

neobotnet runs the same pass on a different in-scope program every week. Subscribe via RSS or browse the company of the week archive.