7 min readCompliance

URL shortener security checklist: 10 controls to verify

Ten security controls to check before you trust a URL shortener: threat-feed scanning, signed webhooks, key hashing, rate limits, audit logs and takedowns.

Sasha Ehrlich
Compliance · EU residency

A short link is an opaque redirect: the recipient can't see where it goes before clicking. That opacity is the product, and it is also why a weakly run shortener becomes an abuse tool. If you're vetting a URL shortener for security, check ten controls, and ask for each answer in writing: destination scanning, signed webhooks, tiered rate limits, hashed API keys, link passwords, expiry caps, an audit log, IP allowlists, bot filtering and SSO. Below, each control comes with what to ask and how Elido implements it, checked against our code on 2026-10-24. Where we fall short, I say so.

The threat model

Four kinds of abuse show up again and again on link infrastructure.

Four-quadrant matrix mapping phishing, leaked API keys, bot-driven analytics inflation, and mass redirect abuse to the control that mitigates each

Phishing and malware. A short link looks the same whether it points to a landing page or a credential-harvesting form. Creating a hundred links takes seconds; cleaning up after they've been distributed takes weeks.

Leaked API keys. Keys end up in client-side JavaScript, public repositories and build logs. If the provider stores them in plaintext, one database leak exposes every customer.

Bot-driven click inflation. Uptime monitors, link-preview fetchers and crawlers all follow short links. Unfiltered, they distort campaign numbers and any volume-based billing.

Mass redirect abuse. One compromised workspace with unlimited API access can create tens of thousands of links an hour and spend the platform's domain reputation on someone else's phishing campaign.

The ten controls

Each control below has the question to put to a vendor and the Elido answer.

Checklist grid of the ten security controls: URL scanning, signed webhooks, tiered rate limits, peppered API key hashing, link passwords, expiration caps, audit log, IP allowlists, bot filtering, and SSO/SCIM

1. Destination scanning, at creation and afterwards

Checking only at creation misses URLs that are clean on day one and listed on day thirty. You need both a synchronous check and a scheduled re-scan.

Elido's url-scanner fans a destination out to up to five sources in parallel: Google Safe Browsing v4, PhishTank, URLhaus, SURBL and an in-house URL-structure heuristic (the heuristic flags xn-- hosts, which is how a homograph lookalike domain gets caught). Which sources run depends on deployment keys and admin policy. The merged score is the maximum across sources: 80 or higher is blocked, 40 to 79 is suspect, below 40 is clean. The create path gives the scan a 250 ms budget. Blocked destinations get a 403 destination_blocked. Suspect ones are queued for a deeper async scan, except on brand-new free workspaces, where a suspect result is rejected outright.

One trade-off to know about: if the scanner is down or too slow, link creation proceeds and the link is marked unknown for a later re-scan. We chose availability over a hard block there.

2. Webhooks signed over a timestamp

Unsigned webhooks give you no way to tell the vendor from someone who found your endpoint URL. Sign the timestamp and body together, or captured payloads can be replayed forever.

Our delivery worker sends v1=HMAC-SHA256(secret, "<unix_timestamp>.<body>") in X-Elido-Signature (aliased as X-Webhook-Signature) with X-Webhook-Timestamp. During a secret rotation it also sends X-Elido-Signature-Previous until the grace window closes. The v1= format will look familiar if you've verified Stripe webhooks. Rejecting stale timestamps is the receiver's job.

3. Rate limits per workspace, by plan tier

IP limits alone fail against rotating addresses, so the binding unit should be the workspace. The API keeps a token bucket per workspace sized by plan (free, paid, business), returning 429 with X-RateLimit-Scope: workspace. If the tier lookup fails, it falls back to the free tier. New free workspaces sit in an "incubator" tier for their first 24 hours: 10 links a day by default, a CAPTCHA on browser-session creation, and a forced synchronous scan. Standard workspaces get 1,000 links a day.

4. API keys hashed with a server-side pepper

Plaintext key storage is indefensible. We store HMAC-SHA256(pepper, key) and show the plaintext once at creation. Lookups hash the inbound bearer token and compare hashes. A fast keyed hash suits long random tokens, and the pepper means a stolen database alone can't be brute-forced. Keys can carry an expires_at; rotation is manual (see the gaps section).

Link passwords are stored as Argon2id hashes (64 MiB, 2 iterations, 4 threads, PHC-encoded), and the API never returns the hash, only a password_set boolean. Be aware of a real gap: as of 2026-10-24 the public redirect service has no password prompt. The check happens on the lookup API (an X-Password header, answered with 401 and password_required: true), so a password on a link is not yet an access gate for people clicking the short URL. Our password-protected links post covers what works today. If you need hard access control, use the end-to-end encrypted link mode or put auth on the destination.

6. Expiry and click caps

Old campaign links stay useful to attackers long after the campaign ends. Links accept expires_at and max_clicks, both enforced on the redirect path. For the lifecycle side, see link expiration and self-destructing links.

7. An audit log you can read yourself

Every mutating action writes an audit event, readable by members with the audit permission at GET /v1/workspaces/{id}/audit. Each row is chained to the previous one by SHA-256 (prev_hash, entry_hash), so edits or deletions are detectable by a verify-chain job. The compliance evidence bundle (.../compliance/evidence.zip) includes the trailing 90 days of events as CSV. Retention is per workspace.

8. IP allowlists

If all legitimate API traffic comes from known ranges, an allowlist turns a leaked key into a much smaller problem. Each workspace can store CIDR prefixes; when the list is enabled and non-empty, other source addresses get 403 even with a valid key. The client address is taken from X-Forwarded-For when present, so make sure your proxy chain is the one you expect.

9. Bot filtering on the redirect path

The edge matches the User-Agent against a list of crawler, preview-bot, uptime-monitor and HTTP-client signatures (about 45 entries), and treats an empty User-Agent as a bot. Matched requests still get their redirect; only the click event is suppressed. A separate scorer marks clicks suspicious, without blocking them, when two or more soft signals fire (no User-Agent, no Accept-Language, a burst from one IP).

10. SSO and SCIM

Per-workspace SSO configuration, domain discovery at GET /v1/sso/discover?domain= and a SCIM webhook let an identity provider handle logins and deprovisioning. Elido doesn't see the password.

A one-afternoon vetting routine

You don't need a penetration test to screen a shortener. Create a free account, shorten a URL you control, then read the response headers and the API docs. Create an API key and see whether the dashboard ever shows it again. Trigger a test webhook and look at the signature headers. Then send the table below to the vendor's support address and time the reply.

Questions to put to any vendor

AskA good answer sounds like
How are API keys stored?An algorithm and whether a pepper is used
How are webhooks signed?HMAC with timestamp inside the signed string
Which threat feeds are scanned?Named feeds, plus a re-scan schedule
Are rate limits per workspace?Yes, and differ by plan
Can admins read an audit log?Self-serve, exportable, tamper-evident
Link password hashing?Argon2id or bcrypt, never MD5 or SHA-256
Bot filtering?Documented, with events suppressed not redirects
IP allowlist per workspace?Yes, CIDR-based

If a vendor can't answer the first, second, third and fifth rows in writing within a business day, the documentation probably doesn't exist.

Where Elido is still hardening

  • Rate limiting is process-local. Buckets are in-memory per replica, so with N replicas a workspace can exceed its limit by up to N times. A shared limiter is planned but not shipped.
  • No WAF. Rate limits, bot filtering and a domain blocklist are what we have. Put an external WAF in front of high-volume public links.
  • Re-scans are periodic, not instant. A sweep runs every six hours and re-checks links not scanned in the last seven days; a newly flagged link is auto-suspended and the owner is notified. A link can stay live for days after a feed lists it.
  • Key rotation is manual. Only an optional expires_at exists.
  • No certification yet. Not ISO 27001 certified; SOC 2 is in preparation.
  • IP addresses are truncated, not removed. The edge cuts them to /24 (IPv4) or /48 (IPv6), but city, coordinates and the full user agent are still stored with each click. Our GDPR checklist covers what that means for you.

Two adjacent reads: open redirect vulnerabilities and QR phishing.

Frequently asked questions

How do I know if a URL shortener is secure?

Ask for specifics in writing and compare them with the ten controls in this checklist. A secure shortener can name the threat feeds it scans destinations against, say how it stores API keys (an algorithm, not a reassurance), sign its webhooks with a timestamp-bound HMAC, rate-limit per workspace, keep an audit log you can read without a support ticket, and describe what happens when a link turns malicious after creation. Vague answers such as 'we take security seriously' are the warning sign.

Can a URL shortener be used for phishing?

Yes. A short link hides its destination until the click, so attackers use shorteners to hide credential-harvesting pages and malware downloads. That is why a serious provider checks every destination against threat feeds at creation, re-scans stored links later, limits how fast new accounts can create links, and removes abusive links quickly after a report.

How should a URL shortener store API keys?

Never in plaintext. The minimum is a one-way hash, and the better design mixes in a server-side secret (a pepper) so a leaked database alone can't be cracked offline. Elido stores an HMAC-SHA256 of each key keyed on a server-side pepper and shows the plaintext token exactly once at creation. Because API keys are long random strings, a fast keyed hash is appropriate for them; slow password hashes such as Argon2id matter for human-chosen secrets like link passwords.

What should a signed webhook include?

A signature computed over both a timestamp and the raw body, plus the timestamp in its own header so receivers can reject stale deliveries. Signing the body alone lets an attacker replay a captured request forever. Elido sends v1=HMAC-SHA256(secret, timestamp.body) in X-Elido-Signature (also aliased as X-Webhook-Signature) with X-Webhook-Timestamp, and during a secret rotation it adds X-Elido-Signature-Previous so receivers can switch keys without downtime.

Does Elido have SOC 2 or ISO 27001?

Not yet. Elido isn't ISO 27001 certified, and SOC 2 is in preparation, so there's no report to hand over today. What exists is the engineering behind the controls in this post, including a tamper-evident hash chain on the audit log and a 90-day evidence export. If a certification is a hard requirement for your procurement, treat that as a current gap and ask before you buy.

Does a URL shortener need a web application firewall?

A shortener's redirect path is narrow: look up a code, return a redirect. That limits injection risk, but it doesn't remove denial-of-service or abuse traffic. Elido applies rate limits, bot filtering and a blocklist feed on the redirect path, but it has no application-layer WAF of its own. High-volume public links are better served by an external WAF or CDN rule set in front of the edge.

Try Elido

Paste a URL, get a working short link

No signup. Link lives for 30 days. Sign up to keep it forever.

No signup needed. Sign up free for 50 links a month.

Try Elido

EU-hosted URL shortener with custom domains, deep analytics, and an open API. Free tier - no credit card.

Tags
url shortener security
secure url shortener
url scanning
webhook signing
api key hashing
phishing link protection

Continue reading