mastra-ai/mastra · error

Push notification host is not allowed: ${hostname}

Error message

Push notification host is not allowed: ${hostname}

What it means

When the sender is configured with an `allowedHosts` allowlist, any push notification destination whose lowercased hostname is not in that list is rejected. This is a host-based SSRF/egress control; the library throws instead of silently skipping so the config owner notices.

Source

Thrown at packages/server/src/server/a2a/push-notification-sender.ts:87

      lookup?: typeof defaultLookup;
      allowedHosts?: string[];
    } = {},
  ) {}

  getStore() {
    return this.pushNotificationStore;
  }

  private async resolveValidatedDestination(rawUrl: string) {
    const url = new URL(rawUrl);

    if (url.protocol !== 'https:' && url.protocol !== 'http:') {
      throw new Error(`Push notification URL must use http or https: ${url.protocol}`);
    }

    const hostname = url.hostname.toLowerCase();
    if (this.options.allowedHosts && !this.options.allowedHosts.includes(hostname)) {
      throw new Error(`Push notification host is not allowed: ${hostname}`);
    }

    if (isDisallowedHostname(hostname)) {
      throw new Error(`Push notification URL must not target local or internal hosts: ${hostname}`);
    }

    if (isDisallowedIpAddress(hostname)) {
      throw new Error(`Push notification URL must not target local or private IPs: ${hostname}`);
    }

    const resolvedAddresses =
      isIP(hostname) === 0
        ? await (this.options.lookup ?? defaultLookup)(hostname, { all: true, verbatim: true })
        : [{ address: hostname, family: isIP(hostname) }];

    if (resolvedAddresses.some(result => isDisallowedIpAddress(result.address))) {
      throw new Error(`Push notification URL resolved to a local or private IP: ${hostname}`);
    }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Add the destination hostname (exact, lowercase) to the allowedHosts option of the push notification sender
  2. Verify the URL hostname matches the allowlist entry exactly, including subdomains
  3. Remove the allowlist (not recommended) if all hosts should be permitted
  4. If the domain legitimately changed, update both the push config URL and the allowlist together

Example fix

// before
new PushNotificationSender({ allowedHosts: ['hooks.example.com'] })
// url host: hooks.example.net -> rejected
// after
new PushNotificationSender({ allowedHosts: ['hooks.example.com', 'hooks.example.net'] })
Defensive patterns

Strategy: validation

Validate before calling

function assertAllowedHost(raw: string, allowedHosts: string[]) {
  const host = new URL(raw).hostname.toLowerCase();
  if (!allowedHosts.includes(host)) throw new Error(`Host ${host} not in allowlist`);
}

Try / catch

try {
  await sender.sendNotifications(task, configs);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Push notification host is not allowed')) {
    logger.error('Push host blocked by allowlist', { err: err.message });
  } else throw err;
}

Prevention

When it happens

Trigger: A push notification config URL targets a hostname (after URL parsing and lowercasing) not present in `options.allowedHosts`, e.g. allowedHosts ['hooks.example.com'] but URL host is 'hooks.example.net' or 'hooks.example.com.' variants.

Common situations: Allowlist drift after infrastructure changes (new webhook domain), trailing-dot or case-normalization mismatches, subdomains not listed (allowlist is exact-match, not suffix match), or testing against localhost while the allowlist only has production hosts.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/207f84d271ba4a4a. Report an issue: GitHub.