fix(web-dashboard): i18n types + reverse-proxy host allowlist#28578
Open
Abhishek21k wants to merge 3 commits into
Open
fix(web-dashboard): i18n types + reverse-proxy host allowlist#28578Abhishek21k wants to merge 3 commits into
Abhishek21k wants to merge 3 commits into
Conversation
Adding the new `scheduled` kanban column to `en.ts` (in both
`columnLabels` and `columnHelp`) broke `tsc -b` because the matching
shape in `types.ts` didn't list the key:
src/i18n/en.ts(661,7): error TS2353: Object literal may only
specify known properties, and 'scheduled' does not exist in type
'{ triage: string; todo: string; ready: string; ... }'.
Declared as optional so the 15 other locale files (af, de, es, fr, ga,
hu, it, ja, ko, pt, ru, tr, uk, zh, zh-hant) remain valid without a
bulk-translation pass — they fall back to the English label, matching
existing i18n behaviour for missing keys.
`_is_accepted_host` rejects any Host header that doesn't match the bound interface (or a loopback alias when bound to loopback). That defence is correct for direct browser-to-loopback access, but it makes the dashboard unreachable behind a reverse proxy or VPN-fronted tunnel: the proxied request arrives on loopback while the browser sends `Host: <public-hostname>`, returning HTTP 400. Today the only escape is `--insecure --host 0.0.0.0`, which disables the DNS-rebinding defence entirely AND requires network-layer trust on every interface. Add an opt-in env var `HERMES_DASHBOARD_ALLOWED_HOSTS` (comma- separated, case-insensitive) checked inside `_is_accepted_host` right after the host is normalised. When unset, behaviour is unchanged; when set, the named hosts are accepted in addition to the bound interface, preserving the rebinding defence for every other Host value.
Adds a short "Reverse-proxy / VPN host allowlist" subsection under the Security warning explaining the new env var: its purpose, comma-separated format, an example invocation, and that the default (unset) preserves existing direct-browser-to-loopback behaviour.
Collaborator
This was referenced May 19, 2026
|
Hey @Abhishek21k — the duplicate-detector bot grouped several dashboard-host-allowlist PRs together; flagging one thing for your awareness. Two observations on this PR specifically:
I opened #29195 covering the host-allowlist surface with the loopback-only placement and 7 regression tests. Let me know if it'd help to consolidate. |
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two small, independent web-dashboard fixes:
web/src/i18n/types.ts— declare the newscheduledkanban column key as optional sotsc -bacceptsen.tswithout forcing a 15-locale translation pass.hermes_cli/web_server.py— add an opt-in env varHERMES_DASHBOARD_ALLOWED_HOSTSso the DNS-rebinding Host-header defence can be paired with a reverse proxy or VPN-fronted tunnel without falling back to--insecure.Each fix is its own commit; docs blurb is a third commit. The env var defaults to unset, so behaviour is unchanged for existing users.
Bug 1 — i18n types missing the
scheduledkeyweb/src/i18n/en.tsadds ascheduledentry to bothcolumnLabels(line 661) andcolumnHelp(line 671), butweb/src/i18n/types.ts(lines 666-683) wasn't updated.tsc -bfails:Declaring the key as optional (
scheduled?: string;) is the minimum-diff fix:en.tsnow type-checks, and the 15 other locale files (af.ts,de.ts,es.ts,fr.ts,ga.ts,hu.ts,it.ts,ja.ts,ko.ts,pt.ts,ru.ts,tr.ts,uk.ts,zh-hant.ts,zh.ts) remain valid without a coordinated translation pass. They fall back to the English label, matching the existing i18n behaviour for missing keys.Bug 2 — Host header rejects reverse-proxied access
Repro
hermes web.dashboard.internalterminating at the loopback bind).https://dashboard.internal/in a browser.The browser sends
Host: dashboard.internal._is_accepted_hostonly acceptslocalhost,127.0.0.1,::1when bound to loopback, so the request is rejected with HTTP 400:Why
--insecureisn't a real workaround--insecurerequires--host 0.0.0.0, which:Fix
Add an env var
HERMES_DASHBOARD_ALLOWED_HOSTS(comma-separated, case-insensitive) checked inside_is_accepted_hostright after the host is normalised. Default unset → no change. When set, the named hosts are accepted in addition to the bound interface; all other hosts are still rejected.The bind stays on loopback, the DNS-rebinding defence stays on for every host except the operator-named ones, and the reverse proxy / tunnel works.
Backward compatibility
HERMES_DASHBOARD_ALLOWED_HOSTSunset → behaviour identical to today. No existing deployment is affected.Test plan
npx tsc -binweb/passes after thetypes.tschange (failed before)._is_accepted_host("localhost", "127.0.0.1")still returnsTrue(loopback alias path unchanged)._is_accepted_host("example.com", "127.0.0.1")returnsFalsewhen env is unset (rebinding defence intact)._is_accepted_host("example.com", "127.0.0.1")returnsTruewhenHERMES_DASHBOARD_ALLOWED_HOSTS=example.comis exported._is_accepted_host("evil.test", "127.0.0.1")returnsFalseeven withHERMES_DASHBOARD_ALLOWED_HOSTS=example.comset (only listed hosts are allowed).HERMES_DASHBOARD_ALLOWED_HOSTS=Example.COMmatchesHost: example.com.Host: example.com:8443matchesexample.com).a,, ,b) don't accidentally allow empty Host headers./reload).