Social Platforms & Creator Networks

One hostile host, ten thousand posts: screening links where they are actually shared

A phishing domain does not arrive on a social platform once. It arrives in a caption, in forty bios, in a burst of replies under a trending post, in direct messages sent from accounts that were themselves taken over last night, and in ad creative submitted from six freshly funded accounts. Screening it means holding the whole list locally and checking at submission — because at post volume, asking a remote service about every link is not an architecture, it is a bill.

390K+DNS-verified domains held locally for submission-time checks
100Domains per /batch request for queue and appeal work
Sub-50msAPI response, when a synchronous check is genuinely warranted
04:30 UTCDaily rebuild, with a changelog for incremental reloads
Post & caption links
Profile & bio URLs
Direct messages
Ad creative review
Appeals & reinstatement
Creator account safety
Home / Use Cases / Social Media Platforms
Where links actually live

A social platform has at least six link surfaces and they behave differently

Teams tend to build link screening for the feed, then discover the same domain has been sitting in a bio for three weeks and moving through direct messages the whole time.

The first thing worth doing on a platform of any size is enumerating every place a user can put a destination, because the list is always longer than the trust and safety roadmap assumes. Captions and post bodies are obvious. Comments and replies are usually covered too. What tends to be missed is everything that is not a piece of content in the ordinary sense: profile bios and the link fields attached to them, pinned link collections, display names that contain a bare hostname, image alt text, the description field on a live broadcast, event listings, group and community descriptions, and the destination on an ad creative, which lives in an entirely separate submission pipeline built by a different team.

1

The surfaces differ in ways that change the design

A caption is written once and read many times, so a check at submission covers the whole lifetime of the post. A bio link is written once, edited freely afterwards, and points at a destination that can change ownership long after the check passed. A direct message is high-trust, low-volume per sender and enormously sensitive to how you handle content. An ad destination is deliberately amplified, carries an implicit endorsement, and is the only surface where somebody paid you for the distribution.

2

An incomplete coverage map is worse than none

It is entirely normal for an attacker to test each surface in turn, find the one that is not screened, and industrialise it. If comments are checked and bios are not, the bios fill up. If the main feed is checked at post time and the edit path is not, everything gets posted clean and edited afterwards. Attackers probe systematically because the cost of probing is close to zero, and a partial system that everyone believes is complete generates a false sense of safety.

3

Check at submission, server-side, before anything is visible

Screening after publication leaves a window in which the link is live and being clicked, and on a platform with velocity that window is where most of the harm occurs. Screening client-side means the check can be bypassed by anybody willing to talk to your API directly, which is precisely the population you are trying to stop. The API key is the username chosen at registration, it is a server-side secret, and it must never appear in a mobile bundle or in page source.

4

Re-screening matters as much as first screening

A domain that was clean when a bio link was set can be compromised, can expire and be re-registered, or can simply have been dormant infrastructure not yet activated. Because you hold the whole database locally and it rebuilds daily, sweeping every stored destination against the current list is a local set intersection rather than an API workload — cheap enough to run nightly across the entire corpus of profile links, pinned collections and active ad destinations.

Posts and captions

Highest volume, simplest lifecycle. Check at submission and again on edit; the destination almost never changes after publication, so one good check covers the whole post.

Bios and link collections

Low volume, long lifetime, frequently ignored. These need daily re-screening far more than posts do, because the destination outlives the check by months.

Direct messages

The highest-trust surface and the most privacy-sensitive. Extract the hostname only, check locally, and never move message content off the platform.

Comments and replies

Where campaign amplification concentrates, because reply threads under trending posts inherit the reach of the original without inheriting its scrutiny.

Ad creative destinations

Paid amplification with an implied endorsement. The one surface where a synchronous check inside the review pipeline is unambiguously worth the latency.

Live, events and groups

Broadcast descriptions, event pages and community about-sections are link surfaces with real reach and almost no moderation attention. Cover them explicitly.

Lures aimed at your own users

Verification badges and copyright strikes are the two that always work

Page administrators and creators are targeted with the two things a platform can take away from them, and both lures arrive dressed as the platform itself.

The most productive social phishing lure in circulation is a message that appears to come from the platform, about the platform, threatening something the recipient genuinely cares about. Two pretexts dominate because they map onto real processes that page administrators already fear. The first is verification: an offer of a badge, a warning that an existing badge is about to lapse, or a request to "confirm eligibility" before a review deadline. The second is a copyright or community-standards strike, usually with a countdown and an appeal link, because an unappealed strike sounds like it ends a business.

Both work because the real process is opaque

They arrive inside the platform, or in mail closely imitating platform notifications, and they concern administrative processes that are genuinely obscure to the people affected. A creator with two hundred thousand followers has probably never seen the real appeals interface, has no mental model of what it should look like, and is under immediate commercial pressure to act. The message does not need to be sophisticated — it needs to be plausible for ninety seconds.

A creator account is a distribution asset, not a personal one

A compromised personal account costs the individual their contacts and their embarrassment. A compromised business page or creator account comes with reach, an established posting cadence that makes new posts look normal, existing advertiser relationships, frequently a linked payment method and ad account that can buy amplification for whatever the attacker posts next — and a direct message inbox full of people who trust it.

Which is why the same hostnames appear in bursts

The attacker is not hand-crafting a page for each victim; they stand up one or a small cluster of hostnames, run them until the destinations stop working, and move on. So once a hostname is observed and verified, blocking it removes the destination from every simultaneous attempt using it — across direct messages, comment replies and tagged mentions. The brand protection page covers imitations of your own domain.

The recovery flow is the surface nobody defends

After an account is compromised the owner searches for help, and the results and replies they encounter are heavily seeded with fake support and recovery services. Somebody who has already lost an account and is desperate to get it back is the least sceptical audience there is, and the second compromise frequently does more damage than the first. Screening replies to distress posts is unglamorous, targeted work with a very high hit rate.

Verification badge offers Copyright strike appeals Community standards warnings Monetisation and payout notices Brand collaboration offers Fake account recovery help Giveaway and prize claims Impersonated support accounts
Submission-time checking

Server-side, before publication, against a list you already hold

The engineering constraint on a social platform is not accuracy. It is that whatever you build has to run inside a request path that is already tight.

Post submission is a latency-sensitive path with a hard budget, and anything you add to it competes with everything else that already lives there — media processing, spam scoring, ranking signals, notification fan-out. That constraint shapes the whole design. A network call to an external service inside the submission path is the wrong shape at any meaningful volume: it adds a dependency whose failure mode is either blocking every post or silently failing open, and it adds a round trip to a path where you are counting milliseconds.

1

Hold the database locally and the problem disappears

The feed downloads as CSV with domain, category and dns_status columns, or as JSON, and several hundred thousand hostnames load comfortably into an in-memory set or a small embedded key-value store on every application host. A lookup is then a hash comparison measured in microseconds, with no network involved, no failure mode depending on somebody else's uptime, and no per-check cost. Feed downloads are unlimited on a subscription, so refreshing often costs nothing beyond bandwidth.

2

The extraction step is where the real bugs live

Take the destination, follow it to a canonical form, and reduce it to the registrable hostname before comparing. Handle the awkward cases explicitly: internationalised domain names normalised to their encoded form, mixed-case input, trailing dots, embedded credentials in the authority section, and shorteners — which need resolving to a final destination before the check means anything, and which have their own page on shortener abuse. A layer that compares literal strings will be bypassed within days of launch.

3

Direct messages need an explicit, narrow policy decision

Users reasonably expect private messages to be private, and any scanning must be justifiable to them in a sentence. The design that survives is narrow: extract only the hostname from a link, compare it against a local list, and never transmit, store or derive anything from the surrounding text. Because the comparison happens on your own infrastructure against a list you downloaded, no third party learns that a message was sent, let alone what it contained — a claim that is architecturally rather than contractually true.

4

Keep the API for everything that is not the hot path

Moderation queues sweeping a backlog. Appeal review, where somebody needs a current verdict on one hostname. Ad creative review, where the pipeline is already asynchronous. Investigations pivoting on a cluster of accounts. All batch or single-item workloads where /batch at a hundred domains per request, one lookup each, with checked, phishing_found and credits_used returned, is the right tool — and where ten requests per second is a comfortable ceiling.

Coordinated spread

The unit of the campaign is the host, not the post

Moderating individual pieces of content against a coordinated campaign is a losing shape. Removing the destination is not.

Content moderation is built around the post: something is reported, reviewed, actioned, and the account accumulates a record. That model works reasonably well for the things it was designed for, and it works very poorly against link-based phishing, because the economics are asymmetric in the attacker's favour. Producing another post costs nothing. Producing another account costs slightly more than nothing. Reviewing a post costs a reviewer's attention, which is the scarcest resource the platform has. A campaign that generates content faster than you can review it wins by arithmetic alone, regardless of how good your reviewers are.

The hostname is the campaign's only fixed asset

It has to be registered, hosted, given working DNS, and — if it imitates a login page — fitted with a plausible certificate. Everything upstream of it is disposable. Blocking one verified hostname therefore neutralises every piece of content pointing at it at once: the posts you found, the posts you did not, the ones in bios, the ones sitting unopened in direct message inboxes, and the ones that have not been posted yet.

Count hostnames, not removed posts

Counting removed posts measures your reviewers' throughput. Counting distinct hostnames blocked, and the volume of content pointing at each, measures the campaign — and the shape of that distribution is informative. A few hostnames carrying most of the blocked content is a coordinated operation and should be escalated as one. A long flat tail is background noise, and treating it as a crisis wastes attention the concentrated cluster deserves.

The changelog shows the lifecycle

Domains added on the same day, imitating the same brand or the same platform process, are usually one operation being stood up. Watching a cluster appear and disappear a week later tells you its lifecycle — and because entries only exist while they have an active A record verified through rotating proxy infrastructure, a removal genuinely means the host stopped resolving rather than that somebody's reporting window closed.

1 : manyOne blocked hostname neutralises every post, bio and message pointing at it
0.98Confidence on a confirmed match; 0.0 for anything not on the list
DailyChangelog of additions and removals, which is how you see a cluster form
LocalEvery check runs on your own hosts, so no user action is disclosed anywhere
Duplicate destination clustering Bulk account enforcement Retroactive inbox sweeps Campaign concentration metrics Transparency reporting
Enforcement & appeals

What happens when you are wrong, at a scale where you will be

Any automated action at platform volume produces mistakes in absolute numbers. The design question is what the mistake costs and how fast it is fixed.

Silently deleting content is the response users hate most and the one platforms reach for most often. It produces no explanation, no route to challenge, and a strong impression of arbitrary enforcement — which is corrosive well beyond the individual case, because the affected user tells other people and the story that circulates is never the accurate one. A domain-based block is unusually easy to explain, and that advantage is worth using rather than discarding.

1

Graduate the response to the surface

An interstitial warning that names what was found and lets the user proceed suits a link in a direct message between two people who know each other. Blocking the destination while leaving the post visible works where the content has value beyond the link. Full removal fits paid ad creative, where the platform is actively amplifying. Whichever you pick, tell the user something specific and truthful — this destination is on a list of domains verified as currently resolving and confirmed as credential harvesting.

2

Binary confidence makes appeals fast

There is no score to interpret and no threshold to argue about: either the hostname is in the database or it is not. A reviewer handling an appeal runs it through /check, reads is_phishing, category, dns_status and last_checked, and has a defensible answer in seconds. When a domain has since been remediated and dropped out, that is visible immediately and the content can be reinstated without a debate.

3

Store the verdict as it was at action time

Record what the verdict was when you acted, not just what it is now, because a domain leaving the database later does not mean the original block was wrong — it means the host stopped resolving. A reviewer who cannot see the original evidence will reinstate correctly-actioned content and, worse, will start to distrust the signal. Storing the check response alongside the enforcement record costs almost nothing and settles a whole category of internal argument.

4

The same records answer a regulator

Platforms operating under proactive-measures obligations are increasingly asked to evidence not just what they removed but what mechanism found it and how current that mechanism was. A dated daily feed, an archived changelog, and per-action records showing the verdict at action time constitute an unusually clean audit trail — and one that does not depend on retaining user content in order to prove anything.

Ad review: the one place to check synchronously

Paid destinations are already reviewed asynchronously, so a call adding tens of milliseconds is invisible in a pipeline measured in minutes. Check the destination at submission, again at approval, and again on a schedule for the life of the campaign — advertisers can and do change landing pages after approval.

Escalate to the account, not the creative. Somebody who funded an account to distribute a verified credential-harvesting page is not a publisher who made a mistake. The adtech and advertising page covers the supply-side view of the same problem.

Direct messages: narrow scope, stated plainly

Extract the hostname, compare against the local list, act on the link rather than the message. No content leaves your infrastructure, nothing is stored beyond the enforcement record, and no third party learns that a message existed.

Write the scope into the policy verbatim. Use the same words your engineers used, and resist scope creep towards content analysis — the narrowness is what makes it defensible. See the messaging apps page for how this plays out where end-to-end encryption is in force.

Re-screening what you already stored

Bio links, pinned collections, event pages and live campaign destinations were checked once, possibly a long time ago. Because the whole database sits locally and rebuilds daily, re-screening the entire stored corpus is a set intersection you can run overnight rather than an API workload you have to budget for.

Order the sweep by reach. A dormant account's bio matters less than the link collection on a page with a large audience, and prioritising by follower count turns a large undifferentiated job into a useful one.

Recovery flows and post-compromise targeting

Users who have just lost an account are the softest target on the platform, and the replies to their public distress posts are reliably seeded with fake recovery services. Screen links in replies to accounts recently flagged as compromised, and in unsolicited messages sent to them.

It prevents the second compromise. Narrow, targeted work with an unusually high hit rate — and the second compromise is frequently the one that takes the payment method with it. The identity protection page covers the account-holder side.

The limitation to write into your own runbook before launch

This is a known-bad lookup and nothing more. A hostname that is not in the database returns 0.0, and that means "not on this list" — never "safe". A domain registered this morning and used for the first time this afternoon will not be present, because the DNS verification that makes the data trustworthy also means an entry cannot exist before the host has been observed and confirmed as resolving. On a platform with real velocity, that window is genuinely exploited.

It is domains, not pages, and it is one layer of several. A hostile page hosted on a compromised legitimate site will not appear, and neither will an attack that never leaves your platform. Treat this as one high-confidence layer beside behavioural signals, account-age heuristics, reporting and human review — excellent at removing confirmed-hostile destinations from your reviewers' attention, and completely silent about everything it has not seen. Any product surface that shows users a green tick based on a 0.0 response is a design error, and it is the kind that gets quoted back at you.
Questions from trust & safety teams

What comes up before this ships

Including the volume objection, the privacy objection and the one about who is accountable when it gets something wrong.

We handle enormous post volume. Can the API keep up?

No, and it is not supposed to. The rate limit is ten requests per second per API key, which is a sensible ceiling for investigation and queue work and nowhere near submission-path volume on a platform of any size. Anyone who tells you a remote per-link call scales to social media volume is describing a bill rather than an architecture.The shape that works is the feed: download the full database daily, hold it in memory or in an embedded store on every application host, and check locally in microseconds with no network call at all. Feed downloads are unlimited on a subscription, so the cost does not move with your traffic. Keep the API for the workloads where volume is small and freshness matters — appeals, investigations, moderation queues and ad review.

How do we justify scanning direct messages to our users?

By keeping the scope genuinely narrow and then describing it accurately. What this requires is extracting the hostname from a link and comparing it against a list you already hold locally. It does not require reading, storing, transmitting or deriving anything from the message text, and it does not tell any third party that a message was sent.That is a materially different proposition from content scanning and it should be described as such, in plain words, in the policy. The strongest version of the claim is architectural: because the comparison happens on your own infrastructure against a downloaded list, there is no outbound request per message that anyone could log, subpoena or correlate. Resist the temptation to broaden the scope later — the narrowness is the entire justification.

What if we block a link that turns out to be legitimate?

Plan for it and it is a support interaction rather than an incident. Verification via an active DNS record keeps the false-positive rate low, but at platform scale a low rate still produces absolute numbers, and pretending otherwise is how you end up with an unstaffed appeals queue.Three things make the difference. Keep a local allow-list applied after every daily import, so an override survives the next reload. Make the notice specific about what was found and offer a route to challenge it. And store the check response as it was at action time, so a reviewer can distinguish "this was never on the list" from "this was on the list and has since been remediated" — the second is not a false positive and should not be recorded as one.

Attackers just use link shorteners. Doesn't that defeat the whole thing?

It defeats a naive implementation, yes. If you check the shortener's own hostname you have learned nothing, because that hostname is legitimate and shared by millions of benign links. The check has to happen against the final destination, which means resolving the chain first.That is standard work for a platform of any size and you probably already do it for other reasons — preview cards, spam scoring, and link attribution all need the destination. Follow redirects with a hop limit, apply the check at each hop and at the end, and be aware that some hostile chains serve different destinations depending on the requesting address or user agent. The URL shorteners page goes into the evasion patterns in more detail.

Does using this feed make us responsible for links we fail to catch?

This is a legal question with a jurisdiction-dependent answer and you should ask your own counsel rather than a vendor page. What can be said factually is that the tool makes a narrow, verifiable claim — a hostname was observed and confirmed as currently resolving credential-harvesting infrastructure — and does not claim to identify everything hostile.In practice, platforms subject to proactive-measures obligations tend to find that a dated, verifiable screening mechanism with an archived changelog and per-action evidence is easier to explain to a regulator than an entirely manual process, precisely because it can be evidenced. Documenting the known limitation honestly is part of that, not a weakness in it. Overstating coverage internally is the failure mode that actually creates exposure.

What does this cost for a platform rather than an enterprise?

The feed is the relevant product, because submission-time screening has to be local. The Daily Threat Feed is $499 per month, with unlimited downloads, and all plans include priority support — which comfortably covers appeals and investigation work without a separate purchase.Note that the cost does not scale with your post volume, which is the property that matters here: whether you screen a million links a day or a hundred million, the subscription is the same because the checks happen on your hardware. Credit packages exist for the API side alone and start at Growth at $99/month for 25,000 lookups; the full table is on the pricing page. , and enterprise delivery over SFTP or S3 is quoted rather than listed.

Our platform is small. Is this only for the large ones?

The architecture is the same at any size — a daily download and a local set membership test is not a big-company technique, and it runs perfectly well on a single application server. If anything, a smaller platform benefits more, because it has no trust and safety headcount to absorb the moderation load that a coordinated campaign generates.Where scale changes the answer is in the appeals path. A large platform needs a self-service appeal flow; a small community can handle it in a support inbox. Do not build the large-platform machinery before you need it, but do decide from day one what a user is told when a link is blocked, because that message is the entire user-facing surface of this system.

Can we show users why a link was blocked without helping attackers test us?

Mostly, yes, and the trade-off is smaller than it first appears. Attackers already know whether their destination works, because they can test it themselves from an ordinary account in seconds. Withholding the reason from a legitimate user therefore costs you goodwill without denying an adversary anything they could not trivially discover.What is worth withholding is timing and mechanism detail — do not tell anybody when your list refreshed, how many entries it holds, or which specific check fired. Say what was found and offer the appeal route. Keep the operational specifics in your own logs, where they inform your enforcement analysis rather than somebody else's evasion testing.

Check destinations where they are submitted, not after they have spread

Read the current database size from the open statistics endpoint, pull one day's file, and intersect it with a week of destinations your own users have posted. The number that decides this is not how large the list is — it is how many links already in your corpus are on it right now.