
Research
/Security News
PolinRider Spreads Through Compromised GitHub Accounts and Packagist
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.
@uekichinos/browser-gate
Advanced tools
Detect outdated browsers and redirect or block access. Supports feature detection (default), minimum version checks, and live latest-version checks via endoflife.date — use one, two, or all three together.
Detect outdated browsers and respond with a built-in notification bar, a redirect, or a callback.
Zero dependencies. Works via ESM, CommonJS, or <script> tag.
npm install @uekichinos/browser-gate
Place in <head> — before your app loads — so outdated browsers are caught early.
<script type="module">
import { browserGate } from '@uekichinos/browser-gate'
// Show a dismissible bar (remembered for a week once closed)
await browserGate({ notify: true, minVersions: { chrome: 100, safari: 15 } })
// …or redirect
await browserGate({ redirect: '/outdated' })
</script>
browserGate(options)Returns a Promise<void>. Resolves silently if the browser passes every check. Otherwise it shows the banner (notify), calls onOutdated, and/or redirects.
await browserGate(options: BrowserGateOptions): Promise<void>
resetBannerReminder()Clears the stored dismissal so the banner can appear again on the next call.
| Option | Type | Default | Description |
|---|---|---|---|
notify | boolean | BannerOptions | — | Show the built-in notification bar (see below) |
redirect | string | — | URL to redirect to when outdated. Suppressed when the banner is shown |
onOutdated | (info: OutdatedInfo) => void | — | Callback; takes precedence over redirect |
features | FeatureKey[] | true | false | true | Feature detection (see below) |
minVersions | { chrome?, firefox?, safari?, edge?, opera? } | — | Minimum version per browser |
checkLatest | boolean | { tolerance?: number | { chrome?, … } } | — | Live latest-version check, with optional per-browser tolerance |
insecure | boolean | false | Flag browsers below a conservative known-safe baseline per engine |
skipBots | boolean | true | Skip all checks when the UA is a bot / crawler / link-preview fetcher |
OutdatedInfo is { browser, version, platform, reasons } — platform is one of 'ios' | 'android' | 'windows' | 'macos' | 'linux' | 'unknown'.
Runs automatically. Checks whether the browser supports five modern APIs:
| Feature | Absent in |
|---|---|
globalThis | IE11, very old browsers |
fetch | IE11 |
Promise.allSettled | Chrome < 76, Firefox < 71, Safari < 13 |
IntersectionObserver | IE11, old Safari |
CSS.supports | IE11 |
// Default — checks all five features
await browserGate({ redirect: '/outdated' })
// Custom feature list
await browserGate({
redirect: '/outdated',
features: ['fetch', 'IntersectionObserver'],
})
// Disable feature detection
await browserGate({
redirect: '/outdated',
features: false,
minVersions: { chrome: 100 },
})
Checks the detected browser version against your thresholds. Only browsers you list are checked — others pass through.
Uses User-Agent parsing. Note: UA strings can be spoofed, so this is best combined with feature detection.
await browserGate({
redirect: '/outdated',
minVersions: {
chrome: 100,
firefox: 100,
safari: 15,
edge: 100,
},
})
Fetches live version data from endoflife.date and checks whether the browser is up to date.
Use tolerance to allow a few versions behind (useful since Chrome releases every 4 weeks).
Fails open on network error, timeout (5s), or unrecognised browser — your users are never blocked due to an API outage.
// Must be on latest
await browserGate({ redirect: '/outdated', checkLatest: true })
// Allow up to 2 versions behind (all browsers)
await browserGate({ redirect: '/outdated', checkLatest: { tolerance: 2 } })
// Per-browser tolerance — Chrome ships every ~4 weeks, Safari ~yearly
await browserGate({
redirect: '/outdated',
checkLatest: { tolerance: { chrome: 4, firefox: 4, safari: 1 } },
})
insecure: true flags browsers below a conservative "clearly unpatched" version per engine, independent of your own minVersions — it catches stale builds on locked-down corporate and Android devices that still pass a feature check.
await browserGate({ redirect: '/outdated', insecure: true })
// reason: "Insecure: chrome 80 is below the minimum patched version (109)"
notify bannernotify: true injects a dismissible, accessible bar (role="alert", fixed to the top) when the browser is outdated — no /outdated page required. Pass a BannerOptions object to customise it.
await browserGate({
minVersions: { chrome: 100 },
notify: {
message: 'Your browser is out of date.', // localised by default
position: 'top', // 'top' | 'bottom'
dismissible: true,
updateUrl: 'https://browsehappy.com', // Apple support page on iOS
reminder: 24, // hours hidden after an auto-show
reminderClosed: 168, // hours hidden after the user closes it (1 week)
lang: 'fr', // default: navigator.language
onShow: (info) => analytics.track('outdated_shown', info),
onClick: (info) => analytics.track('outdated_update_clicked', info),
onClose: (info) => analytics.track('outdated_dismissed', info),
},
})
localStorage (browser-gate:dismissed); the bar stays hidden until the reminder window elapses.resetBannerReminder() clears it.redirect is skipped. onOutdated still fires.en, es, fr, de, pt, ja, zh (falls back to en).skipBots defaults to true — when the User-Agent matches a known crawler, search bot, or link-preview fetcher (Googlebot, Bingbot, Slackbot, Discordbot, GPTBot, …), browserGate returns immediately without redirecting or showing anything. Set skipBots: false to gate them too.
Any failing check triggers the outdated response.
await browserGate({
notify: true,
features: ['fetch', 'IntersectionObserver', 'CSS.supports'],
minVersions: { chrome: 100, safari: 15 },
checkLatest: { tolerance: { chrome: 4, safari: 1 } },
insecure: true,
})
onOutdated callbackUse onOutdated to handle the outdated case yourself (e.g. when you don't want the built-in banner).
await browserGate({
onOutdated: (info) => {
console.log(info.browser) // 'chrome'
console.log(info.version) // '80'
console.log(info.reasons)
// [
// 'Missing feature: IntersectionObserver',
// 'Below minimum version: chrome >= 100 (detected: 80)',
// ]
document.body.innerHTML = `<p>Please update your browser.</p>`
},
})
<script> tag (no bundler)<script src="https://unpkg.com/@uekichinos/browser-gate/dist/index.global.js"></script>
<script>
BrowserGate.browserGate({ redirect: '/outdated' })
</script>
| Browser | Detected via |
|---|---|
| Chrome | Chrome/XX in UA |
| Firefox | Firefox/XX in UA |
| Safari | Version/XX Safari in UA |
| Edge (Chromium) | Edg/XX in UA |
| Edge (legacy) | Edge/XX in UA |
| Opera | OPR/XX in UA |
Unrecognised browsers always pass through.
MIT © uekichinos
FAQs
Detect outdated browsers and redirect or block access. Supports feature detection (default), minimum version checks, and live latest-version checks via endoflife.date — use one, two, or all three together.
The npm package @uekichinos/browser-gate receives a total of 16 weekly downloads. As such, @uekichinos/browser-gate popularity was classified as not popular.
We found that @uekichinos/browser-gate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.

Company News
Allow myself to introduce... myself.