actualbudget/actual · warning
URL not allowed: Only allowlisted plugin repositories are al
Error message
URL not allowed: Only allowlisted plugin repositories are allowed (localhost only in development)
What it means
The CORS proxy only forwards requests to hosts on the plugin repository allowlist (localhost is additionally permitted in development). If the parsed target URL's href is not allowlisted, the proxy responds 403 with 'URL not allowed' and the allowlist-policy message. This is intentional security policy to stop the proxy being used as an open relay.
Source
Thrown at packages/sync-server/src/app-cors-proxy.js:162
} catch {
return res.status(400).json({ error: 'Invalid url parameter' });
}
// Fetch the latest allowlist
try {
await fetchAllowlist();
} catch (error) {
console.error('Failed to fetch allowlist:', error);
return res.status(403).json({
error: 'URL not allowed',
message: 'Unable to verify allowlist',
});
}
// Check if the URL is allowed
if (!isUrlAllowed(url.href)) {
console.warn('Blocked request to unauthorized URL:', url.href);
return res.status(403).json({
error: 'URL not allowed',
message:
'Only allowlisted plugin repositories are allowed (localhost only in development)',
});
}
try {
const { method = 'GET', headers: customHeaders = {} } = req.body || {};
if (typeof method !== 'string') {
return res.status(400).json({ error: 'Invalid method parameter' });
}
const methodNormalized = method.toUpperCase();
if (!['GET', 'HEAD'].includes(methodNormalized)) {
return res.status(405).json({ error: 'Method not allowed' });
}
const requestHeaders = {View on GitHub (pinned to d4334cb6e6)
Solutions
- Change the plugin to fetch only from allowlisted plugin repository hosts.
- If the target repository is legitimate, get it added to the plugin allowlist (or configure a local allowlist) and restart the server.
- In development, use a localhost URL, which the proxy permits.
Example fix
// before
fetch('/cors-proxy?url=' + encodeURIComponent('https://my-cdn.example.com/plugins.json'));
// after: use an allowlisted repository
fetch('/cors-proxy?url=' + encodeURIComponent('https://tantalus.life/plugins.json')); Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED_HOSTS = ['tantalus.life', 'localhost'];
const u = new URL(target);
if (!ALLOWED_HOSTS.includes(u.hostname)) {
throw new Error(`Host ${u.hostname} is not on the plugin allowlist`);
} Type guard
function isAllowlisted(target) {
try {
const u = new URL(target);
return ['tantalus.life', 'localhost'].includes(u.hostname);
} catch { return false; }
} Try / catch
try {
return await proxy(target);
} catch (e) {
if (e.status === 403 && /allowlisted/i.test(e.message)) {
console.error(`Blocked by allowlist policy: ${target}`);
}
throw e;
} Prevention
- Point plugins only at allowlisted plugin repository hosts.
- Check the current allowlist before adding new remote sources to a plugin.
- Use localhost targets during development where permitted.
When it happens
Trigger: A plugin requests an arbitrary API host (e.g. https://api.github.com or a personal CDN) that is not in the allowlist; a request to a non-localhost host while running a production server.
Common situations: Plugin author points fetches at their own repo/endpoint not yet on the allowlist; running localhost-only allowlisting in production by mistake; allowlist updated upstream but server hasn't refreshed it.
Related errors
- URL not allowed: Unable to verify allowlist
- Method not allowed
- Invalid font-family value for "${property}": function calls
- Invalid value "${trimmedValue}" for property "${property}".
- Invalid font src: only data: URIs are allowed in @font-face.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/48274d632f42bbf1.
Report an issue: GitHub.