Links
How MachineMail analyses every link in inbound mail for mismatched text, lookalike and punycode domains, raw IPs, shorteners, brand impersonation and other phishing signals.
Every link in a message gets an entry in trust.links. Links come from HTML anchors (<a> and <area>) and from bare http://, https:// and www. URLs in the text. Entries are deduplicated by target and text, up to 500 per message.
Links are analysed as written. MachineMail does not fetch them, so final_url is not currently set and no request ever reaches the sender’s server because of a check.
Mismatched text: display_mismatch
When the visible text of a link looks like a URL or a domain, its domain is compared with the real destination. display_mismatch is true, and the link counts as suspicious, when:
- the text names a different organisational domain than the target (
Link text says www.paypal.com, href is 198.51.100.23) - the text names a domain but the link goes through a URL shortener (
Link text says stripe.com, but it goes through shortener bit.ly) - the text and target share a domain only once lookalike letters are normalised (
Link text says paypal.com, href is a lookalike domain ...) - a
mailto:link shows one address or domain and mails another
Links through known email click-trackers (SendGrid, Mailchimp, Mandrill, HubSpot, Mailgun, Postmark, SparkPost, Customer.io, Substack, beehiiv, Amazon SES tracking, Proofpoint URL Defense, Outlook Safe Links and others) are expected to differ from their text and are not marked as mismatched.
Link text that is not a URL (“View it in your browser”) is not compared. Subdomains of the same organisation (www.stripe.com text, pay.stripe.com target) match.
Structural red flags: suspicious
suspicious is true when any of these fire. Each adds a line to reasons:
| Signal | Example reason |
|---|---|
javascript: or vbscript: URL | javascript: URL |
data: URL | data: URL (can embed a full phishing page) |
| Unparseable URL | Malformed URL |
| Scheme other than http, https, ftp | Unusual scheme ... |
| Plain http to a login, verify, account, billing or password path | Unencrypted http link to a login/account page |
| Raw IPv4 or IPv6 host | Link points to a raw IP address (198.51.100.23) |
Userinfo before the host, as in https://paypal.com@evil.example | URL contains userinfo before the host (the real host is evil.example) |
| Port other than 80, 443, 8080, 8443 | Non-standard port 8888 |
| Punycode or mixed-script host | Domain uses lookalike characters (pаypal.com imitates paypal.com) or Internationalised (punycode) domain ... |
| Four or more labels above the registrable domain | Excessive subdomains (7 labels) |
| Hostname over 60 characters | Very long hostname |
| A brand name in a domain the brand does not own | PayPal name used in a domain it does not own (xn--pypal-4ve.com) |
| A brand name in a login-style path on someone else’s domain | PayPal login-style path on 198.51.100.23 |
| A link inside hidden HTML | Link is hidden from the human reader |
mailto:, tel:, sms:, cid: and # fragment links are not checked for structural flags.
Brand impersonation
MachineMail keeps a list of brands commonly impersonated in phishing and the domains each one really uses: PayPal, Microsoft, Office 365, Outlook, OneDrive, Google, Gmail, Apple, iCloud, Amazon, Netflix, Facebook, Instagram, WhatsApp, LinkedIn, Dropbox, DocuSign, Adobe, Chase, Wells Fargo, Bank of America, Stripe, Coinbase, Binance, MetaMask, DHL, FedEx, USPS, HMRC, GitHub, Okta, Salesforce, Slack, Zoom, Venmo and Wise.
A brand name inside a host it does not own (paypal-secure-login.example, microsoft.account-verify.example) is flagged, and so is the brand’s name in a credential-style path on a foreign domain. Hosts are compared after lookalike letters are normalised, so a Cyrillic а does not hide the brand. The same list is used by the classifier to catch a display name such as PayPal <service@paypa1-security.com>.
Shorteners
shortener is true for about fifty URL shorteners, including bit.ly, t.co, tinyurl.com, goo.gl, ow.ly, is.gd, rebrand.ly, cutt.ly, dub.sh, lnkd.in, amzn.to and youtu.be. A shortener alone does not make a link suspicious, but it adds URL shortener hides the destination to the link’s reasons, and the classifier counts shortened links against a message that also asks for credentials or payment.
How links feed the verdict
- Any link with
display_mismatchmakes the message at leastsuspicious. - The links component is 10% of the score: 1 minus 0.6 per mismatched link and 0.3 per other suspicious link, never below 0.
- Mismatched links and suspicious links raise
is_phishing. - Reasons for suspicious and mismatched links are copied into the top-level
trust.reasons, prefixed with the link’s domain where needed.
Using link reports in an agent
An agent that browses should not follow a link from mail just because the text looks right:
Better still, only follow links from verified or known mail that the task needs, such as a sign-up confirmation you just triggered. See Using trust in agents.