Writing
Anatomy of an Identity Incident

The Identity Nobody Thinks Is an Identity

Anatomy of an Identity Incident — the City-Forum campaign, 2026. No password was stolen and no vulnerability was exploited. A single server walked out with records from Salesforce and ServiceNow portals through the one identity nobody governs: the anonymous guest.

Michael AbramovichAugust 12, 20266 min read

Forensic write-ups of public identity breaches, strictly at the identity layer. No vendor is the villain — the point is the structural class of failure, not the logo on it.

The 60-second version

Through the summer of 2026, a single server quietly pulled records out of Salesforce and ServiceNow portals belonging to organizations worldwide — telecoms, banks, software vendors including security firms, and public-sector sites. Researchers named the campaign "City-Forum," after a domain tied to the one IP address behind all of it. There was no exploit and no stolen credential. The attacker simply asked the portals for data as an anonymous guest, and the portals answered.

That is the whole story, and it's an uncomfortable one because nothing "broke." Every Salesforce Experience Cloud site and every ServiceNow Service Portal runs unauthenticated visitors as a real, persistent identity — the guest user. If that identity is allowed to read a record, then anyone on the internet can read it, no login required. The attacker didn't defeat authentication; it walked through a door that authentication was never asked to guard, because the failure was in authorization — what the guest identity was permitted to see.

The identity timeline

Only the identity-relevant events.

  • Standing infrastructure (since ~March 2025). A single VPS on commodity hosting, tied to the domain the campaign is named for, sits pointed and ready for well over a year — the same address the whole time, no rotation.
  • The fingerprint. Essentially every request carries the default Go HTTP-client user agent, from one IP, against both Salesforce and ServiceNow across many organizations. That alone marks it as a compiled, purpose-built tool — and a guest session driven by a Go binary has no legitimate explanation.
  • Salesforce enumeration (guest). Against Aura sites, the tool calls the framework's config endpoint to enumerate every object the guest context can reach, then pages through each object's records. On the busiest single target, this produced over 560,000 requests — almost all of it anonymous enumeration.
  • The novel surface (guest, LWR). Against newer Lightning Web Runtime sites — long an offensive blind spot because older tools ignore them — the tool reached the UI-API and its GraphQL endpoint directly, sweeping API versions in sequence to find one that answered.
  • Privilege probing (guest → external user). Alongside the reads, the tool repeatedly hit self-registration endpoints, testing whether a guest could promote itself into an authenticated external user — which typically sees far more than the guest profile does.
  • ServiceNow enumeration (guest). On ServiceNow, the tool hammered a native, barely-documented Service Portal search endpoint at escalating volume — an endpoint that returns the same success code whether you're logged in or not, and hands back real content when the portal's search sources aren't gated.

The pivot point

The pivot is that the guest is a real identity, and its permissions were treated as decoration.

We're trained to think of authentication as the boundary: log in, and you're inside; don't, and you're out. Portal platforms break that intuition. The unauthenticated visitor is logged in — as the guest user, a first-class identity with a profile, sharing rules, and object permissions. You cannot delete it, and requiring login on the site doesn't remove it; the guest identity and everything it can read still exist. So the real question was never "did the attacker authenticate." It was "what did the guest identity have permission to read" — and on these targets, the answer included Accounts, Contacts, Cases, knowledge articles, and more.

Every byte the attacker retrieved was something a site owner had exposed to anonymous users, usually without realizing it. On Salesforce, a guest sharing rule or an over-broad guest profile turns "public website" into "public database." On ServiceNow, a knowledge-base search source with no login gate — often relying on a built-in "any user" access rule that silently resolves true for the guest — returns records to anyone who asks. None of this is a platform vulnerability. It is authorization configuration, on an identity that most teams never picture as an identity at all. That blind spot is the entire attack.

What would have caught it

Naming controls, not products.

Treating the guest as an account you govern. The guest user has a profile, permissions, and sharing rules like any employee. It deserves the same least-privilege review — what can it read, does it still need to, who owns that decision — and almost never gets one. Start by asking your platform what the anonymous guest can currently see.

Locking down the API surface, not just the pages. On Lightning Web Runtime, page visibility and API access are separate controls; a site can look locked to a browser while its GraphQL/UI-API answers anonymous queries. The single strongest lever is disabling guest access to those public APIs unless the site truly needs them.

Auditing portal search sources and read criteria. On ServiceNow, the exposure lives in which search sources a public portal wires up and whether each enforces access. Unconstrained "any user" read criteria and scripted sources with no login gate are the leak; find and scope them.

Disabling self-registration where it isn't required. Open self-registration lets a guest upgrade itself into an authenticated external user — a bigger identity with broader reach. If the site doesn't need public sign-up, turn it off.

Watching for non-human guest traffic. A guest session on a Go, Python, or curl user agent, paging objects or hammering a search endpoint at machine cadence, is anomalous by construction. Portals are driven by browsers; automated guest enumeration is a detectable signal if anyone is looking at guest activity at all.

The last mile

This is the purest last-mile story I've written, because the ownerless identity here is one almost nobody counts.

A Salesforce or ServiceNow portal ships working. Marketing stands up an Experience Cloud site, IT publishes a Service Portal, a few sharing rules get switched on so the public pages render, and the project is "done." The guest identity that quietly underpins all of it — its profile, its permissions, the exact set of records it can read — is never assigned to anyone. Security doesn't review it because it isn't a person and never logs in. The admins who built the site think in pages, not in identities and authorization. So the guest accretes access the way everything ungoverned does: one reasonable "make this visible" at a time, until an anonymous API call returns your customer list. The span between "the portal is deployed" and "someone owns what its anonymous identity is permitted to read" is the last mile, and here it was owned by no one at all.

What makes this version quietly dangerous is that it generates almost no alarm. There's no failed login, no impossible-travel flag, no MFA prompt to defeat — the traffic authenticates as nobody and is served as designed. The attacker held one cheap VPS for a year and a half and let it run, because it never had to break anything. Strong authentication, which the whole industry has poured a decade into, simply wasn't in this fight: the door it guards was standing open beside it, marked "public," leading to data nobody meant to publish. The mile didn't move to a clever new exploit. It moved to the identity we forgot was an identity.

For defenders

Five things you can check this week.

  1. Inventory every guest-facing portal — Salesforce Experience Cloud sites and ServiceNow Service Portals — and, for each, ask the platform exactly what the guest user can read today.
  2. Right-size the Salesforce guest profile and sharing rules, removing object and field access the public pages don't actually need to render.
  3. On Lightning Web Runtime, disable guest access to the public APIs (GraphQL/UI-API) unless the site genuinely requires them — and know this is separate from page visibility.
  4. Audit ServiceNow portal search sources and knowledge-base read criteria for unconstrained "any user" rules and scripted sources with no login gate.
  5. Turn off self-registration where it isn't needed, and alert on guest traffic from non-browser user agents or at non-human request rates.

Built from public research and the tracked indicators; sources below.

Sources

#city-forum #salesforce #servicenow #guest-identity #authorization #last-mile