Skip to content

Cloudflare Workers: document loader rejects public CNAME-backed hosts as private addresses #956

Description

@SJang1

Summary

Fedify's document loader rejects valid public ActivityPub URLs hosted on CNAME-backed custom domains when running on Cloudflare Workers with nodejs_compat.

For example, this public ActivityPub Article cannot be loaded:

https://writings.hongminhee.org/ap/articles/2026/07/fedified-blog

Fedify throws:

UrlError: Invalid or private address: hongminhee-writings.netlify.app.

writings.hongminhee.org is a public hostname whose DNS record points to hongminhee-writings.netlify.app through a CNAME.

Minimal reproduction

import { getDocumentLoader } from "@fedify/vocab-runtime";

const loader = getDocumentLoader();

await loader(
  "https://writings.hongminhee.org/ap/articles/2026/07/fedified-blog",
);

Equivalent Wrangler configuration:

{
  "compatibility_date": "2026-06-16",
  "compatibility_flags": ["nodejs_compat"]
}

Actual behavior

The call fails before the document is fetched:

UrlError: Invalid or private address: hongminhee-writings.netlify.app.

Runtime scope and likely root cause

Fedify's validatePublicUrl() calls:

addresses = await lookup(hostname, { all: true });

and then assumes that every LookupAddress.address is an IPv4 or IPv6 literal:

https://github.com/fedify-dev/fedify/blob/main/packages/vocab-runtime/src/url.ts

Under Cloudflare Workers' node:dns compatibility implementation, the lookup can return the CNAME target hostname—hongminhee-writings.netlify.app.—in the address field instead of a final IP address.

That hostname is passed to validatePublicIpAddress(), which rejects it because it is neither an IPv4 nor an IPv6 literal.

The same lookup under regular Node.js resolves to final IP addresses and does not exhibit this behavior.

Expected behavior

Fedify should successfully load the public ActivityPub document after securely resolving the CNAME target to its final A/AAAA records.

All resolved addresses should still be checked against Fedify's private and reserved address restrictions.

AI disclosure

This issue draft was created using codex:5.6-sol and fixed by @SJang1

Metadata

Metadata

Assignees

Labels

Type

Fields

Priority

None yet

Effort

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions