This project is an informational tool and is not a substitute for the official alerts and instructions of the Israeli Home Front Command (Pikud HaOref). Never rely on it as your sole source of alerts. Always follow official guidance.
Only the latest release is supported. The project follows a rolling release on main;
fixes land there first. (Versions before 1.0.0 were numbered 3.0.0–3.6.0; renumbered
2026-08-30 — see CHANGELOG.md.)
Please report security issues privately — do not open a public issue for an exploitable vulnerability.
- Preferred: open a GitHub Security Advisory (Repository → Security → Report a vulnerability).
- Include: affected file/endpoint, reproduction steps, impact, and a suggested fix if you have one.
You can expect an initial response within a few days. There is no bug-bounty program; this is a volunteer project.
The defaults are safe for local use; before exposing the server publicly:
- Admin password — set
ADMIN_PASSto a strong value. If left unset the server generates a random password at boot and prints it once to the logs (it changes on every restart until you set it). - Admin 2FA — set
ADMIN_TOTP_SECRET(base32) to require a live 6-digit authenticator code alongsideADMIN_PASSfor/adminand/metrics. - HTTPS — terminate TLS via a reverse proxy (Caddy / nginx / Cloudflare). Required for Web Push and to protect the Basic-auth admin credentials in transit. See the README.
- Rate limiting — the built-in limiter is 120 req/min/IP; put a proxy/WAF in front
for production-grade protection. Note it (and the admin audit log) trust the
X-Forwarded-Forheader for the client IP — fine behind a real reverse proxy that sets it, but spoofable if the raw Node process is exposed directly to the internet. - Secrets —
.vapid-keys.json,.push-subs.json, and.store-snapshot.jsonare git-ignored. Never commit them. Useflyctl secrets/ env vars for credentials.
These are deliberate and should not be reported as bugs:
- Open CORS (
Access-Control-Allow-Origin: *) — the read API is meant for public consumption (embeds, third-party dashboards). - CSP allows
'unsafe-inline'— the client is a single monolithic HTML file with inline CSS/JS by design. - No authentication on read endpoints (
/api/alerts,/api/stream,/api/logs, etc.) — the data is public alert information; only/adminand/api/admin/*require credentials./api/logsserveslogs/alerts.log, which contains nothing beyond what/api/alertsand/api/historyalready expose publicly. POST /api/client-erroris unauthenticated by design — it's a public error-reporting sink, gated only by the global rate limiter. It's self-limiting (rotated at 10MB × 5 files), so the worst case is old genuine error reports getting rotated out faster under abuse, not unbounded disk growth.
GitHub reported 8 alerts (1 critical, 2 high, 5 moderate) the first time
pnpm-lock.yaml was committed — Dependabot can only scan a lockfile once it's
tracked in git, so this was a first-visibility event, not a new regression.
- 7 of 8 (
request,form-data×2 including the critical one,qs×2,uuid,tough-cookie) all traced to the same chain: the deprecatedrequest/@cypress/requestHTTP client pulled in transitively bynode-telegram-bot-api@0.66.0(anoptionalDependency, used only by the standalonetelegram-bot.js). That library's only actual use in this repo wasnew TelegramBot(token, {polling:false})+bot.sendMessage(...)— a single Telegram Bot API call. Fixed:telegram-bot.jswas rewritten to POST toapi.telegram.orgdirectly viahttps(same pattern assendDiscord()inserver.js), andnode-telegram-bot-apiwas dropped frompackage.jsonentirely. This removes the whole vulnerable chain and needs nonpm installstep anymore. - 1 of 8 (
js-yaml, high, quadratic-CPU DoS in!!omapparsing) comes fromeslint@9.39.5→@eslint/eslintrc(adevDependency, only runs locally/in CI, never in the deployed server). The project never parses untrusted YAML anywhere inserver.js/index.html/lib.js— the only YAML file is the static, developer-authoredopenapi.yaml, which is served as-is and never fed throughjs-yaml. Accepted, not fixed: eslint only drops this dependency in its v10 line, which requires migrating.eslintrc.jsonto flat config (eslint.config.js) and raising the supported Node version to^20.19 || ^22.13 || >=24(the project currently declaresengines.node: >=18) — out of proportion to a lint-only, non-exploitable advisory. Revisit if/when the project bumps its minimum Node version.
- The server stores only alert data (city, type, timestamp) — no user accounts, no PII.
- Web Push subscriptions (
.push-subs.json) contain browser endpoints + chosen favorite cities; they never leave your server. - Client preferences (language, theme, favorites, DND) live in the browser's
localStorage/IndexedDBand are never transmitted except as Web Push favorites. logs/admin-audit.logrecords every/admin//metricsauth attempt (timestamp, success/ failure, IP, path) — never served over HTTP, file-system access only.logs/client-errors.logrecords client-reported JS errors (message, stack trace, page URL, User-Agent) — also file-system access only, never served over HTTP.- Git commit history uses only the GitHub-provided
users.noreply.github.comaddress, never a personal email.