tg.pe is a small, free URL shortener run by one person. This is an honest look at what it does behind every link, and how it handles the people who try to weaponise it for phishing and scams.
If you are a security researcher, network operator, or internet-governance reader, the numbers, methodology, and full change history are in For researchers below.
A stranger reported a scam
A German-language parcel-delivery phishing mail reached Stefano with a “Pay now” button on a tg.pe link. He forwarded it to abuse@tg.pe: “this looks like a SPAM Mail and abuse of your service.” 50 minutes later the link was a 404, the account banned, the destination block-listed. His reply: “Awesome, didn't expect a reply.” The default experience of reporting abuse online is a black hole; what makes the difference here is not budget, it is that someone is paying attention.
The numbers
Service usage
Short links created (lifetime)
31,674
Removed for safety / abuse
2,152 (6.8%)
Active links currently served
29,522
Total clicks served (since April 2026)
94,410
Service age
6 years 8 months
Abuse handling
External abuse reports received (lifetime, from CERTs / vendors / individuals)
313
Median time from external report to removal
~4 hours
Submitters currently banned
206
Legal interactions
Law-enforcement requests, court orders, DMCA / UDRP / URS notifications, and acquisition / policy-change inquiries received in 6+ years: 0 across the board. Full position in Who runs it & your data.
How links stay safe
Every link is checked before it goes live, checked again in the background moments later, and then re-checked when it is clicked, at most once a week per link, not on every click. None of these checks is perfect; each catches what the others miss. The slow ones run after the response is flushed, so nobody waits while they finish.
tg.pe runs no ads and sells no data; it redirects to the exact URL submitted and strips platform trackers (fbclid, gclid, igshid) first.
Who runs it & your data
Operator: Sean Wei, an individual in Taiwan 🇹🇼. No company, no legal entity, no business model; tg.pe is free and the operator absorbs all costs.
What is shared: nothing that identifies a submitter. Only the destination of a confirmed-malicious link (its URL and domain, never who submitted it) is reported onward to abuse feeds.
Everything above is the short version. What follows is the depth: the measurement and data first, then the engineering of the safety pipeline, then the ecosystem and outcomes, written for security researchers, network operators, and internet-governance readers, with the methodology and the open questions kept honest throughout.
Measurement & data: domain age and RDAP coverage
For every destination, tg.pe resolves the age of the registrable parent domain and records which source answered. RDAP is tried first; when RDAP is silent (typically a ccTLD outside the IANA bootstrap), CIRCL Passive DNS first-seen serves as a second tier; and a VirusTotal WHOIS-derived creation date is a further fallback in the background pass. The synchronous resolver (resolveDomainAge()) tags its answer as rdap or pdns; the background VirusTotal pass records its own source=virustotal in malicious_detections separately.
That source tag is the interesting part. It turns a routine safety check into a small, live, reproducible instrument for a real DNS-abuse-governance question: where is RDAP actually answering, and where does the ecosystem still fall back to weaker signals? The sections below report what the instrument has shown so far. All of it is preliminary and open: a curiosity this tooling could be extended into a study, not a settled result.
The two-population domain-age picture
Observed in practice, on a small sample: the destinations split into two populations. Freshly-registered throwaway domains are caught early, at submission, by the new-domain and smartlink honeypots; they never reach a human. The destinations that instead reach an operator takedown after an external report tend to be compromised, established sites, where the registration date says nothing useful about intent. This is an observation, not a rate: the usable sample is small, partly because legacy removals scrubbed the destination before the registration date was retained (see the gaps list). Treat it as a shape worth probing, not a finding.
RDAP bootstrap coverage (preliminary)
RDAP coverage observed in practice is uneven. gTLDs are essentially complete in the IANA RDAP bootstrap; ccTLD coverage is patchy. The Peru .pe ccTLD (tg.pe's own TLD) is absent from the bootstrap, which is precisely why CIRCL Passive DNS first-seen is needed as a second tier at all. And bootstrap presence understates real deployment: several registries run RDAP servers that are not listed in the bootstrap (unlisted or "stealth" servers), so a TLD can be answering RDAP while reading as uncovered.
Three method disclosures are needed before any coverage figure from this tooling is cited, because each one biases what "covered" means here:
The resolver follows rdap.org, not a self-maintained bootstrap parse. Lookups go to rdap.org, a bootstrap-following aggregator that redirects to the authoritative server. The coverage tg.pe sees is therefore mediated by rdap.org's behaviour, not by a first-hand reading of the IANA bootstrap file.
eTLD+1 is a hardcoded two-level-suffix list, not the Public Suffix List. The registrable-domain extraction (rdapRegistrableDomain()) recognises a fixed set of co.uk/com.tw-style suffixes and otherwise falls back to the last two labels. On an unlisted multi-label ccTLD this can query the wrong parent, which biases coverage exactly on the TLDs the measurement is most interested in.
The pDNS first-seen proxy is biased. CIRCL first-seen is the earliest time CIRCL's sensors observed the domain in DNS, not its registration date. A long-dormant domain only recently observed reads as "new". This is acceptable in the pipeline (pDNS only fires on an RDAP miss, and a hit creates an operator-reviewed honeypot, not a hard block) but it is a real bias in any measurement built on the same datum.
The reproducible figure to publish is the RDAP-hit vs pDNS-fallback vs VT-fallback rate, broken out by gTLD vs ccTLD, ideally a small per-TLD table, each row pinned to a snapshot date, an observation window, and a denominator. Until that query is run against the live source tag, no ccTLD-coverage number is stated here.
The open direction this points at: a per-ccTLD study joining stealth-inclusive RDAP deployment (probing for unlisted servers, not just reading the bootstrap) with response conformance (does the server actually return a usable registration event?). tg.pe's source-tagged data is one small, real-world input to that, no more.
Methodology & definitions
“Removed for safety / abuse” = short_links.deleted_at IS NOT NULL, both automated re-check removals and manual operator removals.
“Banned submitters” = entries in banned_users.
Country code = CF-IPCountry at submission time (Web only); VPS/VPN endpoints read as rented infrastructure, not the submitter's residence.
Clicks are counted only since the April 2026 SQLite→MySQL migration; earlier clicks are not counted.
Cache TTLs a reimplementer needs: a registration date is immutable, so it is cached 30 days; reputation is mutable, so it is cached 1 day.
This report is generated from a snapshot of the production MySQL database plus the operator's mail archive.
The safety pipeline: architecture & rationale
tg.pe layers its checks at three points: before a link goes live, after the response has been flushed to the client, and again on every later click. The split is deliberate. The synchronous checks are the ones cheap enough to add to the user-visible latency budget; everything slow runs strictly after the response is flushed, so it adds safety without adding latency anyone feels. The stage table below makes the blocking/non-blocking boundary explicit, and the design notes explain the non-obvious choices. This is the part most directly reusable by another small operator; the contact section means that invitation seriously.
Stage-by-stage
Grouped by where each stage runs. The Blocking? column marks which checks are strictly pre-response (they add latency the submitter waits on) versus strictly post-flush (no user-visible latency). Fail-mode is what happens when the external dependency is unavailable.
Stage
Data source
Blocking?
On hit
Fail-mode
Logged to
Before the link goes live (synchronous, adds latency)
Domain blacklist & high-risk list
Local curated lists
Blocking
Blacklist (47): refuse on both channels. High-risk (353): refuse on Web only; identified Telegram users pass.
n/a (local)
submission_rejects
Newly-registered-domain check
RDAP (via rdap.org); CIRCL pDNS second tier
Blocking
Web < 30 days / Telegram < 7 days → one-hour honeypot, operator notified. ccTLD with no RDAP falls to pDNS first-seen.
Threat-category match → refuse before the short link is created.
Fail-open: API error lets it through, logged
error log + submission_rejects
Submitter rate limit
Local counters
Blocking
Two-layer: Web 5/hr (anon non-TW) up to 20/hr (identified) plus a 10-minute burst cap; Telegram 60/hr plus a 20-per-10-min burst cap → refuse. The burst layer is what stops the cron-bot spikes.
n/a (local)
rate_limit_hits
After the response is flushed (background, no user-visible latency)
VirusTotal reputation + creation date
VirusTotal v3 /domains
Post-flush
Malicious verdict (≥ VT_MALICIOUS_MIN = 2 engines) or brand-new on an RDAP-missed TLD → tighten link to 30-min expiry. Whitelist: telegra.ph, graph.org, t.me (Telegram-owned, abused on sub-paths only) are never flagged.
Fail-open (any VT failure / rate-limit leaves the link untouched)
malicious_detections
urlscan.io capture
urlscan.io
Post-flush
New-domain / VT honeypots get a screenshot, redirect chain, contacted hosts. Runs on urlscan's infrastructure → hostile page never fetched from tg.pe's server. Becomes evidence for onward reports.
Fail-open (no capture, no penalty)
capture stored with the link
Submitter IP screen
AbuseIPDB
Post-flush
New non-Taiwan Web submissions scored; AbuseIPDB confidence score > 75 → link expired within a second or two of creation. Never runs for Telegram.
Fail-open
error log
Google Safe Browsing: re-check on later clicks
Google Safe Browsing API
Post-flush (after redirect sent)
Only if last check > 7 days; atomic claim so concurrent clicks check once; flagged → removed, operator notified.
Honeypot, not hard refusal. A brand-new-domain or smartlink submission is created with a one-hour expiry rather than refused; the submitter sees success while the operator is notified at once. A hard refusal would hand the adversary a clean feedback signal ("this destination is flagged, rotate it") which the honeypot deliberately denies.
urlscan.io scopes the SSRF claim precisely. The capture runs on urlscan's own infrastructure, so a hostile page is never fetched from tg.pe's server. This is not a claim that tg.pe never contacts destinations. RDAP and VirusTotal lookups are made by tg.pe directly; the precise claim is only that the page-rendering fetch of a flagged hostile destination is offloaded.
Fail-open Safe Browsing is an honest tradeoff and an admitted attack surface. A GSB API error lets the submission through and is logged, rather than blocking legitimate users on Google's downtime. The honest counterpoint: a GSB outage is a window, and it is named as a known limitation. The mitigation is that it is logged and the next click triggers a fresh check, not that the window doesn't exist.
The click-driven re-check is atomically claimed. Re-scanning ~30,000 idle URLs daily would burn API quota for nothing; the re-check instead fires the moment someone is about to be exposed, and only if the last check is > 7 days old. To stay safe under concurrency, the work is claimed atomically before it runs, so a burst of concurrent clicks on the same stale link triggers exactly one re-check, not one per click.
The ordering/latency contract. Synchronous stages complete before the redirect is emitted; the connection is then flushed and closed, and only after that do VirusTotal, urlscan.io, the AbuseIPDB screen, and the GSB re-check run. A link a background check flags is expired seconds later, live too briefly to circulate, but the submitter never waited on the check.
Asymmetric trust. Web is anonymous and mutable, so it gets the stricter thresholds (30-day new-domain window, tighter rate limits, no custom codes, the AbuseIPDB screen). Telegram identity is durable and bannable, so it is trusted further (7-day window, higher rate limit, high-risk list bypassed); one ban then clears that user's whole history.
What the automation catches
The logging is built to measure the defence funnel, not just to fire alerts. EventLog::logReject() writes one row per failing stage into submission_rejects, by design, so the operator can measure how much each stage caught on its own versus in overlap across blacklist / new_domain / safe_browsing / abuseipdb; and malicious_detections records the source, reason, and engine counts for each background tightening. The data to publish a per-stage funnel (how many submissions each stage caught, how much each stage caught uniquely, and the marginal value of each external dependency) already exists; at this n it must be clearly labelled as small.
One slice is reportable now. Of the background VirusTotal scans run since that pass went live, 49 tightened a just-created link to a 30-minute expiry with no operator in the loop, split below. The denominator (49 of how many total background scans) is what turns this from an anecdote into a measurement, and that count belongs in the funnel table above.
Malicious reputation verdict
42
Brand-new domain on an RDAP-missed TLD
7
Shown honestly, this is also where the layers overlap: some of these 43 would have been caught by another stage too. The funnel table is the place to show which stages are redundant and which are load-bearing, rather than implying every layer is independently essential.
Where links come from
Most links come from identified Telegram users via @tgpebot; the rest from the anonymous Web form and a few API integrations. The chart breaks the Web share down by submitter country (Cloudflare's CF-IPCountry at submission, so VPS/VPN endpoints in FI/NL/US/RU read as rented infrastructure, not the submitter's real location). Click a legend item to focus it.
Telegram dominates volume every year. Within Web, Taiwan led 2019 and 2022; from 2020 on, Russia dominates; legitimate users mixed with automated probes. The 2025 Web spike came overwhelmingly from RU/US automated submissions (sharp single-hour UTC peaks consistent with cron-driven bots); most appear to have been caught at the safety pipeline, though the per-stage catch rate is not yet quantified (see the funnel above).
By channel, and where removed abuse came from (charts)
Total submissions by channel (Web / Telegram / API), with unique submitters overlaid:
Of the links that were removed, where did the submitter sit? Telegram is deduplicated to distinct users so ban cascades don't inflate it; Web stays per-link.
The asymmetry the charts show is structural. Telegram carries more removed links than its lighter submission-time gates would suggest a problem with: because identified users face fewer front-door checks, more slips through at submission, but it is caught later, by external reports, the 7-day click-driven re-check, or manual review, and a single ban then clears that user's entire history. Web, by contrast, is filtered hard at the front door, so less reaches the point of removal. (The per-channel counts are read off the charts above.)
When links get shortened (submission-rhythm heatmaps)
Submissions over the last 104 weeks, day-of-week × hour-of-day in UTC, Web vs Telegram:
Web, anonymous form submissions
00
06
12
18
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Telegram, user submissions
00
06
12
18
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Less
More
Web shows sharp isolated peaks at exact UTC hours, the signature of cron-scheduled bots. Telegram's heat is diffuse across the week, human use across many timezones. That asymmetry is the reason Web gets stricter rate limits and new-domain thresholds than Telegram. A well-trodden supporting visual; it confirms the trust split rather than driving it.
What people shorten
Top destination hosts among active links (self-referential tg.pe links excluded):
Host
Active links
t.me
2,225
drive.google.com
1,191
telegra.ph
1,188
hinet.net
1,016
docs.google.com
876
facebook.com
822
elnacional.cat
556
1024tera.com
484
Mostly messaging-app deep links, cloud-file sharing, and Taiwan-local content.
Click distribution (the long tail)
Click counting started in April 2026 (the SQLite→MySQL migration), so earlier clicks aren't counted. Among links clicked since then, split by submission channel (API excluded):
Click bucket
Web
Telegram
1 – 10 clicks
441
1,698
11 – 100 clicks
83
129
Over 100 clicks
24
11
Removal & response
Removal authority comes from the public Terms every submitter accepts: phishing, malware, scams, CSAM, harassment. One Telegram ban soft-deletes every link that user ever created. Re-check is click-driven: a click on a link not checked in the last 7 days triggers a fresh Safe Browsing call. The verified figure is a ~4-hour median from external report to removal; that median describes active response, not all removals, because backlog cleanup and ban-cascade sweeps are much older and would otherwise pull it out of shape. The tables below are the integrator's database output.
Removal timing & re-check volume (tables)
Time from creation to removal
How old each link was when it came down. The top group is active response to fresh abuse; the bottom group is backlog cleanup and ban-cascade sweeps, whose timings reflect when the operator audited, not when the abuse was first detected.
URL age at removal
Removals
%
Active response
Under 1 hour
62
7.3%
1 – 24 hours
220
26.0%
1 – 7 days
201
23.8%
Backlog cleanup & ban cascade
7 days – 1 year
297
35.1%
Over 1 year
65
7.7%
Excludes 1,296 links soft-deleted in a single batch on 2025-01-06 21:24, a one-time inventory cleanup whose synthetic timestamps would distort the distribution.
Re-check coverage
Live Google Safe Browsing calls fired against existing short links since the April 2026 integration:
Window
Live re-checks
Last 7 days
679
Last 30 days
2,644
All-time (since integration)
3,104
The other ~25,000 active links pre-date the Safe Browsing integration; their last_safety_check_at was backfilled to creation date at the April 2026 migration. Their first live check fires on the next click. Most never get one (see the long tail under Click distribution), which is by design: idle URLs shouldn't burn API quota until somebody is about to be exposed.
Abuse reports & real cases
External reports come from national CERTs, anti-fraud vendors, and ordinary recipients. Over the service's life the top three sources (CIRCL, the US IRS, and Netcraft) are ~76% of volume; the long tail confirms tg.pe sits on multiple watchlists.
The candid part is the misses, and what each one changed. The worst category (July 2022): a Tor-routed report flagged a tg.pe link as the entry point to a child-sexual-abuse archive; the operator confirmed and removed it within 8 hours. It is the only non-phishing abuse case in 5+ years, and the reason takedown, block list, and bans apply equally to the worst categories, not just phishing. 2022 IRS campaign: IRS auto-detection forwarded 73 reports and CIRCL added 108 (~199 in two quarters, more than every other quarter combined); ASN-level banning was rolled out in response. European bank clones (2021–2023): Société Générale, Crédit Agricole, La Poste, Deutsche Postbank, Alpha Bank, ČSOB, each reported by a different organisation, each removed within hours. Orange France (April 2021): a two-week run of 15+ links to cloned Orange login pages; the operator removed each and hand-banned the submitter IPs, part of why IP/ASN blocking became core.
Reporters & yearly volume (chart & table)
Yearly volume and response time
Reports = external incoming. Links reported = distinct tg.pe/{code} short links named in those reports. Response time = median time from first report to removal.
Year
Reports
Links reported
Response time
Notes
2026 (YTD)
4
2
2.4 h
Includes the parcel-delivery scam reported by an ordinary user (the featured case above).
2025
18
3
4.6 h
Q4 spike (mail-server-side incident, not tg.pe-shortened content); same-day handling.
2024
8
3
5.2 h
Mostly Netcraft; same-day handling.
2023
39
7
2.9 h
Volume dropped; remaining reports handled within hours.
2022
207
26
5.1 h
IRS impersonation + CIRCL bulk wave, the largest sustained external pressure to date.
2021
25
37
2.5 h
First-line defences built (see timeline). Many reports came as multi-code batches.
2020
12
2
4.8 h
First reports arrived (Cloudflare / Netcraft / DigitalOcean). Tiny volume.
The 2022 row is the most meaningful: even at peak external pressure, median report-to-removal held ~5.1 hours.
Reporting abuse onward
Removing a link from tg.pe does not remove the threat from the internet. When the operator confirms a removed destination is malicious and classifies it, the indicator is reported onward to the abuse-handling community (feeds, vendors, and registrars) so the underlying page can be acted on wherever else it is reaching people. Each report goes only to the channels that fit it; a mis-routed report burns reporter reputation, which is the scarce resource here.
The volume is small and deliberate. Counting only successful sends: 13 outbound reports, 3 distinct destinations, 7 channels reached, 3 via API and 10 assisted-manual. The seven channels are CIRCL MISP, abuse.ch ThreatFox, Netcraft, the DNS Abuse Institute's NetBeacon, Google Safe Browsing, Microsoft SmartScreen, and phish.report. MISP events carry machine-readable taxonomy tags: TLP:GREEN, source:tg.pe, an incident classification, and the destination's registration age, the same registration-age datum the new-domain check resolves (the measurement section). CSAM is never sent to these phishing/malware feeds; it is referred out of band to NCMEC, the IWF, or law enforcement.
Per-channel breakdown (where the 13 went)
Channel
Method
Reports
Netcraft
manual
3
Google Safe Browsing
manual
2
Microsoft SmartScreen
manual
2
NetBeacon
manual
2
phish.report
API + manual
2
abuse.ch ThreatFox
API
1
CIRCL MISP
API
1
All were phishing or scam; no malware or CSAM has been routed to these feeds.
A report that closed the loop (and one that didn't)
One case is documented end to end. On 25 May 2026 a tg.pe link to a Flipkart-impersonation phishing page on gauseva.life was removed and reported to five channels. On 2 June 2026 phish.report confirmed the domain suspended by its registrar (case case_fn4ae2bso6ps), eight days from removal to suspension, with an external reference the operator did not generate. The honest counterpoint from the same period: a cloaked affiliate smartlink reported to Netcraft came back "no threats found"; monetisation redirectors serve benign content to datacentre scanners, so not every report closes. This is n=1 closed and n=1 not. It is not evidence that reports lead to takedowns, and nothing here should be read as "typically" or "usually". What fraction of onward reports end in a confirmed removal is not yet measured (see the gaps list).
Bans & domain lists
206 submitters are currently banned, all Telegram users; a ban soft-deletes every link that user ever created. No Web submitter has ever been individually banned; Web abuse is stopped upstream by the safety pipeline, and Web IPs are too mutable to ban usefully. The verified central figure is a median of 2 links before a ban; the higher percentiles are integrator database output, below.
Domain lists
List
Count
Examples
Behaviour
Block list
47
Phishing landing pages, malware distribution sites
Refused on both Web and Telegram.
High-risk list
353
Other URL shorteners, free hosting platforms
Refused on Web only; identified Telegram users pass.
Links-before-ban distribution (206 banned accounts)
Median (50th percentile)
2
75th percentile
3
95th percentile
11
Legal position & data handling (full)
Operator: Sean Wei, an individual in Taiwan 🇹🇼. No company, no legal entity, no business model; tg.pe is free and the operator absorbs all costs.
What is stored: short code + destination URL, submitter identifier (Telegram ID, or IP + country code for Web), timestamps, last Safe-Browsing check time, click count. Removed records are kept indefinitely as audit history.
Requests: phishing / malware / CSAM removed immediately regardless of who reports (no legal standing needed); a legitimate destination is not removed just because a brand owner dislikes it; submitter-identification only via a Taiwan court order under the PDPA; government takedowns without a legal basis are not honoured.
Legal interactions to date: zero, no subpoenas, court orders, DMCA / UDRP / URS, or acquisition / policy-change offers in 6+ years. If that changes, a future revision will say so.
Jurisdiction: the operator is under Taiwan law (PDPA); the .pe registry is in Peru, with no contact to date.
Safety-mechanism timeline
The change history, paired where relevant with the miss each fix responded to.
2026 Jun: CIRCL MISP outbound publication operational (taxonomy-tagged community events); urlscan.io evidence capture; the AbuseIPDB IP screen and the click-time Safe Browsing re-check moved to post-response background passes (expire-on-flag) to keep latency off the hot path; first externally-confirmed closed-loop takedown.
2026 May: smartlink-pattern detection; CIRCL Passive DNS online as the RDAP second tier; OpenPGP key published via Web Key Directory; the outbound contributor pipeline went operational.
Phished-brand attribution. The large majority of reports are phishing, but the operator has not yet tagged which brands are most often impersonated. This requires per-message body analysis that is in progress.
Closed-loop takedown rate. One outbound report is confirmed all the way to registrar suspension and one cloaked smartlink did not close. What fraction of onward reports end in a confirmed removal (and how it splits between throwaway phishing registrations and cloaked monetisation redirectors) is not yet measured.
Registrable-domain age at scale. The two-population shape is probable from this data, but the usable sample is small because legacy removals scrubbed the destination. Retaining the destination and its source-tagged registration date on every removal going forward would turn this into a population statistic, closing the loop back to the measurement section.
RDAP coverage as a published figure. The source tag already records RDAP-hit vs pDNS-fallback per lookup; a per-TLD coverage table (with snapshot date and denominator) is a query away but not yet published.
If anything here is useful (for research, for policy work, or if you run a similar service and want to compare notes), please reach out. tg.pe is a small operation, but small operators are part of how URL-level abuse gets contained, and the operator would rather share than keep it private.