iOfficeAI/AionUi · error · Error
update.errors.hostNotAllowed
update.errors.hostNotAllowed
Error message
update.errors.hostNotAllowed
What it means
Thrown by assertAllowedUrl when the URL's hostname is not in ALLOWED_DOWNLOAD_HOSTS. The updater uses a strict allowlist so downloads/redirects can only hit known-good hosts (e.g. GitHub, the project CDN), blocking SSRF-style exfiltration through the update channel.
Source
Thrown at packages/desktop/src/process/bridge/updateBridge.ts:282
const resolveRepo = (requestRepo?: string): string => {
const envRepo = process.env.AIONUI_GITHUB_REPO?.trim();
const repo = (requestRepo || envRepo || DEFAULT_REPO).trim();
return repo || DEFAULT_REPO;
};
const assertAllowedUrl = async (rawUrl: string) => {
let parsed: URL;
try {
parsed = new URL(rawUrl);
} catch {
throw new Error((await getI18n()).t('update.errors.invalidUrl'));
}
if (parsed.protocol !== 'https:') {
throw new Error((await getI18n()).t('update.errors.httpsOnly'));
}
if (!ALLOWED_DOWNLOAD_HOSTS.has(parsed.hostname)) {
throw new Error((await getI18n()).t('update.errors.hostNotAllowed', { host: parsed.hostname }));
}
};
const fetchWithAllowlistedRedirects = async (rawUrl: string, signal: AbortSignal): Promise<Response> => {
let current = rawUrl;
for (let i = 0; i <= MAX_REDIRECTS; i++) {
await assertAllowedUrl(current);
const res = await fetch(current, {
signal,
redirect: 'manual',
headers: {
'User-Agent': DEFAULT_USER_AGENT,
},
});
if (res.status >= 300 && res.status < 400) {View on GitHub (pinned to 711aa0550e)
Solutions
- Use an allowlisted host (check the ALLOWED_DOWNLOAD_HOSTS constant in updateBridge.ts for the accepted set)
- If you self-host, add your host to ALLOWED_DOWNLOAD_HOSTS in a fork/local build
- Verify you are not accidentally redirecting to an off-list CDN
- Confirm DNS/mirror config serves from the expected allowlisted domain
Example fix
// before const ALLOWED_DOWNLOAD_HOSTS = new Set(['github.com']); // after (self-hosted setup) const ALLOWED_DOWNLOAD_HOSTS = new Set([ 'github.com', 'releases.mycompany.com', ]);
Defensive patterns
Strategy: validation
Validate before calling
import { ALLOWED_DOWNLOAD_HOSTS } from './updateBridge';
const isAllowedHost = (u: string): boolean => {
try { return ALLOWED_DOWNLOAD_HOSTS.has(new URL(u).hostname); } catch { return false; }
};
if (!isAllowedHost(downloadUrl)) throw new Error('host not in update allowlist');
await fetchWithAllowlistedRedirects(downloadUrl, signal); Type guard
const isAllowlistedHost = (u: string): u is string =>
(() => { try { return ALLOWED_DOWNLOAD_HOSTS.has(new URL(u).hostname); } catch { return false; } })(); Try / catch
try {
await fetchWithAllowlistedRedirects(url, signal);
} catch (err) {
if (err instanceof Error && err.message.includes('hostNotAllowed')) {
// surface to user: this mirror/host is unsupported; fall back to GitHub releases
} else throw err;
} Prevention
- Document the allowlisted hosts to users
- Keep the allowlist in sync with any new CDN you adopt
- Fall back to the GitHub release path when CDN host is rejected
When it happens
Trigger: Passing an update URL whose host is not on the allowlist — e.g. a self-hosted release server, a GitHub Enterprise host, or a proxy domain. The failing hostname is interpolated into the message via the host variable.
Common situations: Self-hosting releases behind a custom domain; corporate mirrors; pointing the updater at a staging host that was never allowlisted; the allowlist constant edited/removed during refactoring; redirects that land on a CDN host outside the list.
Related errors
- update.errors.httpsOnly
- update.errors.invalidUrl
- update.errors.redirectNoLocation
- update.errors.tooManyRedirects
- update.errors.githubApiFailed
AI-assisted analysis of iOfficeAI/AionUi@711aa0550e (2026-08-28).
Data as JSON: /api/errors/74c8c475e4b2e2dc.
Report an issue: GitHub.