Skip to content

fix: prevent browsers from caching link redirects#302

Open
n-WN wants to merge 1 commit into
miantiao-me:masterfrom
n-WN:fix/no-store-redirects
Open

fix: prevent browsers from caching link redirects#302
n-WN wants to merge 1 commit into
miantiao-me:masterfrom
n-WN:fix/no-store-redirects

Conversation

@n-WN

@n-WN n-WN commented Jun 2, 2026

Copy link
Copy Markdown

Problem

Link redirects are issued with sendRedirect(event, finalTargetUrl, +redirectStatusCode) and no Cache-Control header. Since redirectStatusCode defaults to 301, browsers cache the redirect persistently.

The practical consequence: after you edit or delete a link in the dashboard, the server correctly returns the new target / a 404 (verified with curl), but any browser that already visited the old short link keeps redirecting to the stale target from its local 301 cache — the request never reaches the worker again. For a shortener whose links are mutable by design, this looks like "deleted links still work."

Fix

Set Cache-Control: no-store on both redirect paths (the device-specific redirect and the default redirect), so every visit re-hits the worker and reflects the current link state.

This mirrors the no-store already applied to the password / unsafe-warning / cloaking HTML responses in the same middleware. It is a minimal, behavior-preserving change — the redirect status code is left untouched (still configurable via NUXT_REDIRECT_STATUS_CODE); no-store simply stops clients from caching the hop.

Testing

  • Before: curl -I /<slug>301 with no Cache-Control; deleting the link still resolves in a browser that visited it earlier.
  • After: curl -I /<slug>301 + cache-control: no-store; edits/deletes take effect immediately on next visit.
server/middleware/1.redirect.ts | 4 ++++
1 file changed, 4 insertions(+)

Link redirects are sent via sendRedirect() with no Cache-Control header.
With the default redirectStatusCode of 301, browsers cache the redirect
persistently, so a link that is later edited or deleted in the dashboard
keeps resolving to the old target on the client (the request never reaches
the worker again). This is surprising for a shortener whose links are
mutable by design.

Set 'Cache-Control: no-store' on both redirect paths (device redirect and
the default redirect) so every visit re-hits the worker and reflects the
current link state. Mirrors the no-store already used for the password /
unsafe-warning / cloaking HTML responses.
@miantiao-me

Copy link
Copy Markdown
Owner

Thanks for raising this.

I understand the concern: for editable/deletable short links, browser-side caching of 301 redirects can lead to stale behavior.

That said, the redirect status code is already configurable via NUXT_REDIRECT_STATUS_CODE. Deployments that prefer non-permanent redirect semantics can switch to 302 or 307 first.

I am not fully sure we should force Cache-Control: no-store on all redirects by default, because some users may intentionally use 301 and rely on its permanent redirect / SEO behavior. The caching behavior is also part of that choice.

For now, I would prefer not to change the current redirect caching behavior in this PR. Let us keep it open and see what others think.

@n-WN

n-WN commented Jun 6, 2026

Copy link
Copy Markdown
Author

In principle, this kind of short link sharing shouldn't be considered a security measure by SEO. Of course, this is just my personal opinion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants