---
title: "Link Scanners and One-Time Secrets | LinkPilot Blog"
description: "How URL unfurlers and security scanners can accidentally burn one-time secrets — and the patterns that defend against it."
lang: en
json-ld: |
  [
    {
      "@context": "https://schema.org",
      "@type": "SoftwareApplication",
      "@id": "https://uselinkpilot.com/#software",
      "name": "LinkPilot",
      "applicationCategory": "BusinessApplication",
      "operatingSystem": "Web",
      "description": "LinkPilot is a secure link management platform for creating branded short links, tracking engagement, and sharing secrets with expiring, protected, self-destructing links.",
      "url": "https://uselinkpilot.com",
      "offers": [
        {
          "@type": "Offer",
          "name": "Free",
          "price": "0",
          "priceCurrency": "USD",
          "url": "https://uselinkpilot.com/pricing"
        },
        {
          "@type": "Offer",
          "name": "Pro",
          "price": "29",
          "priceCurrency": "USD",
          "priceSpecification": {
            "@type": "UnitPriceSpecification",
            "price": "29",
            "priceCurrency": "USD",
            "billingDuration": "P1M"
          },
          "url": "https://uselinkpilot.com/pricing"
        },
        {
          "@type": "Offer",
          "name": "Agency",
          "price": "299",
          "priceCurrency": "USD",
          "priceSpecification": {
            "@type": "UnitPriceSpecification",
            "price": "299",
            "priceCurrency": "USD",
            "billingDuration": "P1M"
          },
          "url": "https://uselinkpilot.com/pricing"
        },
        {
          "@type": "Offer",
          "name": "Enterprise",
          "priceSpecification": {
            "@type": "PriceSpecification",
            "priceCurrency": "USD"
          },
          "url": "https://uselinkpilot.com/pricing"
        }
      ]
    },
    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "@id": "https://uselinkpilot.com/#organization",
      "name": "LinkPilot",
      "url": "https://uselinkpilot.com",
      "parentOrganization": {
        "@type": "Organization",
        "@id": "https://tetracorehq.com/#organization",
        "name": "TetraCore",
        "url": "https://tetracorehq.com/"
      },
      "logo": {
        "@type": "ImageObject",
        "url": "https://uselinkpilot.com/logo-512.png",
        "width": 512,
        "height": 512
      },
      "description": "LinkPilot is a secure link management platform for creating branded short links, tracking engagement, and sharing secrets with expiring, protected, self-destructing links.",
      "sameAs": [
        "https://x.com/uselinkpilot",
        "https://www.linkedin.com/company/uselinkpilot",
        "https://facebook.com/uselinkpilot"
      ]
    },
    {
      "@context": "https://schema.org",
      "@type": "WebSite",
      "name": "LinkPilot",
      "url": "https://uselinkpilot.com",
      "potentialAction": {
        "@type": "SearchAction",
        "target": "https://uselinkpilot.com/blog?q={search_term_string}",
        "query-input": "required name=search_term_string"
      }
    },
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "position": 1,
          "name": "Home",
          "item": "https://uselinkpilot.com"
        },
        {
          "@type": "ListItem",
          "position": 2,
          "name": "Blog",
          "item": "https://uselinkpilot.com/blog"
        },
        {
          "@type": "ListItem",
          "position": 3,
          "name": "Link Scanners and One-Time Secrets",
          "item": "https://uselinkpilot.com/blog/link-scanners-and-one-time-secrets"
        }
      ]
    },
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "@id": "https://uselinkpilot.com/blog/link-scanners-and-one-time-secrets#article",
      "headline": "Link Scanners and One-Time Secrets",
      "description": "How URL unfurlers and security scanners can accidentally burn one-time secrets — and the patterns that defend against it.",
      "datePublished": "2026-05-26",
      "dateModified": "2026-07-14",
      "image": "https://uselinkpilot.com/logo-512.png",
      "author": {
        "@type": "Person",
        "name": "W. Miller",
        "worksFor": {
          "@type": "Organization",
          "name": "LinkPilot",
          "url": "https://uselinkpilot.com"
        }
      },
      "publisher": {
        "@type": "Organization",
        "name": "LinkPilot",
        "url": "https://uselinkpilot.com",
        "logo": {
          "@type": "ImageObject",
          "url": "https://uselinkpilot.com/logo-512.png",
          "width": 512,
          "height": 512
        }
      },
      "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://uselinkpilot.com/blog/link-scanners-and-one-time-secrets"
      }
    },
    {
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [
        {
          "@type": "Question",
          "name": "Which clients are the worst offenders?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Anything that unfurls URLs: Slack, Microsoft Teams, iMessage, LinkedIn DMs, WhatsApp web previews, and most email security gateways (Mimecast, Proofpoint, Microsoft Defender). They all fetch the URL on receipt."
          }
        },
        {
          "@type": "Question",
          "name": "Can I detect unfurlers by user agent?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Partially. Well-behaved bots send identifiable user agents (Slackbot-LinkExpanding, LinkedInBot, Twitterbot). Security scanners often spoof real browsers, so user-agent filtering alone is insufficient."
          }
        },
        {
          "@type": "Question",
          "name": "Is GET-vs-POST a complete fix?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "It handles the unfurler case completely, since unfurlers only issue GET. It doesn't handle a human accidentally clicking and burning the secret — for that you also need the passphrase gate."
          }
        },
        {
          "@type": "Question",
          "name": "Do email scanners ever click buttons on the page?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Some detonation sandboxes execute JavaScript and can interact with a page, so a bare reveal button is not a guarantee. That's why the passphrase gate matters: a sandbox cannot supply a passphrase that traveled through a different channel."
          }
        },
        {
          "@type": "Question",
          "name": "How do I test whether a secret-sharing tool is unfurl-safe?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Create a throwaway secret, fetch its URL once with curl (a plain GET — exactly what an unfurler does), then open it in a browser. If the browser shows 'already viewed,' the tool burns on GET and is not safe to paste into chat or email."
          }
        }
      ]
    }
  ]
---

[![LinkPilot](/link_pilot_icon.webp)LinkPilot ](/)

[Features](/features)[Tools](/tools)[Blog](/blog)[Pricing](/pricing)[FAQ](/#faq)

Toggle theme [Sign In](/login)[Start free](/signup)

1.  [Home](/)
2.  [Blog](/blog)
3.  [Security](/blog/category/security)
4.  Link Scanners and One-Time Secrets 

[Security](/blog/category/security)

# Link Scanners and One-Time Secrets

How URL unfurlers and security scanners can accidentally burn one-time secrets — and the patterns that defend against it.

By W. Miller · May 26, 2026 · 8 min read

If your [one-time link](/glossary#one-time-link "Glossary: one-time link") is consumed on `GET`, it dies the moment Slack unfurls it. Here's why it happens, which systems fetch your links without asking, and how to design around all of them.

## The default failure mode

Most chat and email clients try to render a preview when they see a URL. The flow looks like this:

1.  User pastes the [secret link](/glossary#secret-link "Glossary: secret link") into Slack.
2.  Slack's unfurler fetches the URL (issues `GET`).
3.  Your reveal handler treats the request like a human view, burns the secret, and returns the payload.
4.  Slack receives the burned payload (or a generic page) and renders it.
5.  The [human clicks](/glossary#human-clicks "Glossary: human clicks") the link, sees "already viewed," and pings the sender for a new one.

The unfurler had no malice. Your handler conflated "someone fetched the URL" with "the recipient read the secret." Those are different events, and the entire design problem is keeping them apart.

There's a worse variant hiding in step 3: if the unfurler's `GET` received the actual payload, the secret now sits inside a third party's preview-rendering infrastructure. Best case, it was discarded after the preview was built — but you have no way to confirm that, and no audit event telling you it happened.

## Who actually fetches your links

"Slack unfurls previews" understates the problem. A URL pasted into a modern workplace is typically fetched by several systems before any human clicks it:

Fetcher

When it fires

Identifiable?

Chat unfurlers (Slack, Teams, iMessage, WhatsApp, LinkedIn)

The moment the message is sent

Usually — distinct user agents such as `Slackbot-LinkExpanding`

Email security gateways (Mimecast, Proofpoint, Microsoft Defender)

On delivery, and often again at click time

Often not — many present real browser user agents

Endpoint protection / antivirus

When the URL reaches the recipient's machine

Rarely

Corporate web proxies

At click time, before the user's request is forwarded

Rarely

Link-preview browser extensions

On hover or page load

No — they ride the user's own browser session

Vendor behavior in this table is a moving target — treat specific gateway claims as "as published July 2026, verify against current docs." The common thread doesn't move, though: every one of these systems issues a plain `GET`, because that's the only safe, universal way to look at a URL you don't control.

## The fix: separate fetch from reveal

The [HTTP](/glossary#http "Glossary: http") semantics are already there. RFC 9110 defines `GET` as safe and idempotent — a request anyone may issue freely because it isn't supposed to change anything. `POST` is the action verb. So treat the reveal as a `POST` action behind a visible button:

```http
GET  /s/abc123   →  HTML page: "Click to reveal this secret"
POST /s/abc123   →  burns the secret, returns the payload
```

Now Slack's `GET` returns a neutral metadata page. The secret only dies when the human clicks the button. Any scanner that respects HTTP semantics — nearly all of them, since issuing side-effectful `POST`s against arbitrary URLs would break half the web — never touches the payload at all.

## A worked trace

Follow one link end to end. You create a secret with [burn-after-read](/glossary#burn-after-read "Glossary: burn-after-read") and a passphrase, then paste the URL into a Slack DM and an email.

1.  **Slack's unfurler** issues `GET /s/abc123`. Response: a small metadata page — status active, passphrase required. No view recorded. Secret alive.
2.  **The recipient's email gateway** rewrites the URL in the email and fetches it at delivery time for reputation analysis. Same `GET`, same metadata. Still alive.
3.  **The recipient clicks the emailed link.** The gateway's click-time scanner fetches once more (`GET`), then redirects the browser onward.
4.  **The browser loads the reveal page** — another `GET`. The page shows a reveal button and a passphrase field. Still no view recorded.
5.  **The recipient enters the passphrase and clicks reveal.** The browser issues `POST /s/abc123`. The view is recorded, the payload is returned, the secret burns.
6.  **Anyone fetching the URL afterward** gets an explicit "already viewed and destroyed" response instead of content.

Five fetches, one reveal. That ratio is normal in a corporate environment — any design that can't tolerate it will fail on day one, and the sender will just paste the password into chat instead.

## Layered defenses

### The GET / POST split

Handles every well-behaved unfurler and scanner, which is the overwhelming majority of automated traffic. This is the foundation; everything below is depth.

### Passphrase gate

Covers what the split can't: sandboxes that execute JavaScript and interact with the page, plus accidental human clicks and forwarded emails. A detonation sandbox can click a reveal button; it cannot supply a passphrase that traveled through a different channel. Send the link by email and the passphrase by Slack DM or SMS.

### Bot user-agent filtering

Drop known preview bots (`Slackbot`, `LinkedInBot`, `Twitterbot`) before they reach any reveal logic. Worth doing as belt and braces, but never sufficient alone: security scanners routinely present real browser user agents precisely so malicious pages can't cloak themselves from analysis.

### Short expiry

Bound the damage window. A link that lived for fifteen minutes leaves scanners, log files, and chat history holding a URL that no longer resolves to anything.

### Cache-Control: no-store

Set it on every reveal response so no intermediary — corporate proxy, [CDN](/glossary#cdn "Glossary: cdn"), browser cache — retains a copy of the payload after the one legitimate read.

## Email security gateways specifically

Corporate gateways deserve their own section because they fetch twice. Products in this class rewrite every URL in inbound mail through their own scanning domain. The URL is typically fetched once at delivery for reputation analysis, and again at click time, before the human is redirected to the real destination.

If either fetch burned the secret, the recipient would _always_ see a dead link — a failure mode that looks random to users but is completely deterministic. The `GET`/`POST` split absorbs both fetches for free, since both are plain `GET`s. The click-time [redirect](/glossary#redirect "Glossary: redirect") then lands the human on the reveal page, where the `POST` happens.

## Edge cases that still bite

-   **JavaScript-executing sandboxes.** Some detonation environments render the page and interact with it. A `POST` behind a button _without a passphrase_ could, in principle, be clicked by an aggressive sandbox. The passphrase gate is the backstop.
-   **Link and passphrase in the same channel.** If both travel in one email, every defense above collapses to "hope nobody reads that email." Always split channels.
-   **Forwarding.** Every forward into a new chat or mail system triggers a fresh round of unfurls. Harmless with the split — but each hop is another set of logs holding the URL, which is an argument for short expiry.
-   **Concurrent reveals.** If two people click reveal simultaneously, the burn must be atomic: exactly one request wins and the other gets "already viewed." A non-atomic implementation can serve the payload twice.

## Test your own tool

Before trusting any secret-sharing service with real credentials, run this two-minute check:

1.  Create a throwaway secret with burn-after-read enabled.
2.  Fetch it from a terminal — this is exactly what an unfurler does: `curl -s -o /dev/null -w "%{http_code}" "<url>"`
3.  Open the link in a browser. If you see "already viewed," the tool burns on `GET` and is not safe to paste into chat or email.
4.  If it survived, reveal it properly in the browser, then `curl` again — you should now get an explicit gone/burned response, not the payload.

## How LinkPilot implements this

For the record, this is the design LinkPilot's Secret Links use: a `GET` on the reveal endpoint returns metadata only (status, and whether a passphrase is required); a view is recorded only on an explicit `POST` reveal. Passphrases are SHA-256 hashed client-side and rate-limited to five attempts per IP per minute per secret. Every reveal response carries `Cache-Control: no-store`, burned or expired secrets return HTTP 410 with the stored payload overwritten, and the audit timeline records each event with a hashed IP under a daily-rotating salt — the raw IP is never stored. Full details live on the [security architecture](/security-architecture) page.

Try it free, no signup

### Burn-After-Read Secret

Share a message that destroys itself after one view.

[Open tool](/tools/burn-after-read-secret)

## Limits of this design

Honest boundaries: none of the above protects a secret _after_ a legitimate reveal — the recipient can copy, screenshot, or forward the payload itself. It doesn't help if the passphrase travels with the link. And it can't stop a human who was mistakenly sent the link from opening it before the intended recipient does — that's what the audit trail is for: you see the unexpected view, and you rotate the credential.

## Related reading

-   [How one-time secret links work](/blog/how-one-time-secret-links-work)
-   [Why URLs leak sensitive information](/blog/why-urls-leak-sensitive-information)
-   [LinkPilot Security Architecture](/security-architecture)

## Tools mentioned in this article

[

Burn-After-Read Secret

Share a message that destroys itself after one view.







](/tools/burn-after-read-secret)[

Free Secret Link Generator

Send encrypted, self-destructing messages securely.







](/tools/free-secret-link-generator)

## Frequently asked questions

### Which clients are the worst offenders?

### Can I detect unfurlers by user agent?

### Is GET-vs-POST a complete fix?

### Do email scanners ever click buttons on the page?

### How do I test whether a secret-sharing tool is unfurl-safe?

## Run smarter links with LinkPilot

Tracking, UTMs, QR codes, AI insights, and white-label reporting — in one workspace. Free to start.

[Create your free account](/signup)

## Read next

[

Security

### OneTimeSecret vs Privnote vs Password Pusher: Which Should You Use?

A three-way comparison of the most popular secret-sharing tools — encryption, expiry, revocation, self-hosting, and where each one genuinely wins.





](/blog/onetimesecret-vs-privnote-vs-password-pusher)[

Security

### Is Privnote Safe? An Honest Security Assessment (2026)

Privnote's core mechanism works, but clone-site phishing, closed source code, and zero auditability are real risks. Here's a fair assessment and safer setups.





](/blog/is-privnote-safe)[

Security

### How to Send a Password Securely (Without Leaving It in Chat Forever)

The safest way to send a password is a one-time encrypted link that self-destructs after viewing. Here's every method ranked, with the trade-offs spelled out.





](/blog/how-to-send-a-password-securely)

On this page

-   [The default failure mode](#the-default-failure-mode)
-   [Who actually fetches your links](#who-actually-fetches-your-links)
-   [The fix: separate fetch from reveal](#the-fix-separate-fetch-from-reveal)
-   [A worked trace](#a-worked-trace)
-   [Layered defenses](#layered-defenses)
-   [The GET / POST split](#the-get-post-split)
-   [Passphrase gate](#passphrase-gate)
-   [Bot user-agent filtering](#bot-user-agent-filtering)
-   [Short expiry](#short-expiry)
-   [Cache-Control: no-store](#cache-control-no-store)
-   [Email security gateways specifically](#email-security-gateways-specifically)
-   [Edge cases that still bite](#edge-cases-that-still-bite)
-   [Test your own tool](#test-your-own-tool)
-   [How LinkPilot implements this](#how-linkpilot-implements-this)
-   [Limits of this design](#limits-of-this-design)
-   [Related reading](#related-reading)

![LinkPilot](/assets/link_pilot_icon-Bslvq5xV.webp)LinkPilot 

[About](/about)[Features](/features)[Pricing](/pricing)[For Agencies](/url-shortener-for-agencies)[Tools](/tools)[Blog](/blog)[Glossary](/glossary)[Compare](/compare)[Privacy](/privacy)[Security](/security-architecture)[Transparency](/transparency)[Terms](/terms)[GDPR](/gdpr)

[](https://x.com/uselinkpilot)[](https://www.linkedin.com/company/uselinkpilot)[](https://facebook.com/uselinkpilot)

© 2026 TetraCore. All rights reserved. · LinkPilot is [a TetraCore product](https://tetracorehq.com/)