Skip to content

security: the default modules refuse a private or loopback host (O55, 0.29.0) - #194

Merged
mark1russell7 merged 10 commits into
client/audit2-securityfrom
client/audit2-host-fetch-policy
Oct 25, 2026
Merged

mark1russell7 merged 10 commits into
client/audit2-securityfrom
client/audit2-host-fetch-policy

Conversation

@mark1russell7

Copy link
Copy Markdown
Owner

The host fetch policy break of O55, split out of #181 by release decision D35. It ships alone as 0.29.0, after the PATCH release of #181 and the shim. Do not merge before that release.

Base: client/audit2-security (#181). After #181 merges, this PR is retargeted to main (or main is merged into it).

What changes:

  • weather.forecast of the default weatherModule refuses a baseUrl on a loopback, private or link-local address: FORBIDDEN, reason host-not-allowed.
  • The mcpHostModules of @procedures/bundle-assistant (geo, ics; used by the dev-tools server) refuse such a host.
  • createHostFetch() loses the deprecated option warnOnRefusal (and its three notices PROCEDURES_WEATHER_PRIVATE_HOST, PROCEDURES_GEO_PRIVATE_HOST, PROCEDURES_ICS_PRIVATE_HOST).
  • The READMEs and tests go back to the refusal of the first version of security: audit pass 2 fixes (O55) #181.

Changeset: minor for @procedures/http, @procedures/weather, @procedures/bundle-assistant (MINOR: a break, pre-1.0), with the migration steps for the site, MiniMongo, Graph and jarvis (none of them needs a change).

The commit is the revert of b5d974a (the PATCH commit of #181), except the changeset of #181.

🤖 Generated with Claude Code

The break that the PATCH of #181 deprecates. weather.forecast and the
mcpHostModules of geo and ics refuse a loopback, private or link-local host
with FORBIDDEN (host-not-allowed). createHostFetch() loses the deprecated
option warnOnRefusal. A minor changeset gives the migration steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mark1russell7 and others added 9 commits October 25, 2026 10:21
The draft keeps its own bundle-assistant test: the refusal of 0.29.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* security: audit pass 2 fixes (O55)

- client: procedure.delete and procedure.define obey the expose rule of
  the host (R17). A hidden procedure is not found, and define refuses a
  hidden path with NOT_EXPOSED.
- mcp-server: a task without a session is visible only to requests
  without a session, and such a request does not see HTTP session tasks.
- restic: restic.run refuses --from-password-command, --password-command2,
  the program options of sftp and rclone in each spelling, sftp and rclone
  repositories whose host or remote starts with "-", and a positional
  argument that starts with "-" after a last flag without a value.
- http: createHostFetch(), a GET fetch through the host policy.
- weather: weather.forecast goes through createHostFetch() by default,
  createWeatherModule({ fetch }) for a server of the host.
- geo, ics: createGeoModule({ fetch }) and createIcsModule({ fetch }), the
  refusal of the policy keeps its code. bundle-assistant gives them
  createHostFetch().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bundle-assistant: keep the default geo and ics modules in the global registry

The site build and mark import the register entries of geo, ics and the
bundle into the global registry. The bundle's copies of geo and ics with
the host fetch have other handlers, so the registry refused the second
ics.fetch. The register entry of the bundle now gives the default modules
of geo and ics. bundleAssistantModule, which the dev-tools server gives
to createRegistry(), keeps the host policy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* client: procedure.define refuses only to replace a hidden procedure

The first fix refused each define at a hidden path. The dev-tools host
test of R23 defines a new procedure at a free hidden path, a working
call shape. The check now refuses only a path where a hidden procedure
exists, so a caller still cannot replace a procedure that it cannot see.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bundle-assistant: give geo and ics with the host policy as mcpHostModules

mark registers the ./module default of each package in one registry,
one package at a time. The bundle's copies of geo and ics with the host
fetch have other handlers, so geo and ics then did not load. The bundle
keeps the default modules now, and exports mcpHostModules: geo and ics
with createHostFetch(). The dev-tools server gives the mcpHostModules of
its bundles to createRegistry() before the bundles. In one call, the
first module of a name counts, so they replace the default modules
there, as a host does with createHttpModule().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: correct the STE findings of the O55 README changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: regenerate PACKAGES.md for the http dependency of weather and bundle-assistant

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* O55 PATCH: a private or loopback host still works, with a deprecation notice (D35)

createHostFetch() gets the deprecated option warnOnRefusal. With it, a host that
the policy refuses gets one DeprecationWarning for each code in the process, and
the request goes through the global fetch, as on main. Without it, the refusal
throws FORBIDDEN, as before.

The default weather module and the mcpHostModules of bundle-assistant (geo, ics)
use the option. Each notice names the fix:
createWeatherModule / createGeoModule / createIcsModule({ fetch: createHostFetch({ allow: [...] }) }).
The refusal by default moves to client/audit2-host-fetch-policy (0.29.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(bundle-assistant): read process through globalThis: the tests have no types of Node

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… keep working (D35) (#195)

- tailscale: createTailscaleModule({ executable }) / createTailscaleProcedures(),
  and TAILSCALE_EXE. The input executable is @deprecated and emits
  PROCEDURES_TAILSCALE_EXECUTABLE_INPUT one time in the process.
- restic: the executable option of createResticModule(). The input executable is
  @deprecated and emits PROCEDURES_RESTIC_EXECUTABLE_INPUT.
- mail: MAIL_PASSWORD_ENV. A passwordEnv without IMAP_ or MAIL_ still works and
  emits PROCEDURES_MAIL_PASSWORD_ENV.
- notify: NOTIFY_TOKEN_ENV. A tokenEnv without NTFY_ or NOTIFY_ still works and
  emits PROCEDURES_NOTIFY_TOKEN_ENV.

The patch changeset lists the five upcoming breaks (0.29.0 to 0.33.0) with the
migration steps for the site, MiniMongo, Graph and jarvis.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the low findings of the second code audit (O57)

Fixes 18 of the 19 low findings of audit pass 2 in 11 packages, each with a
test, as PATCH changes. writeIcs writes the EXDATE of an event with a tzid
in that zone (round-trip test for America/Los_Angeles at 20:00).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(server): type the output of server.create in its test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(pdf): copy the checked file to the output, no rename fallback

The fallback for a rename across drives had no test. The temporary
folder goes in finally, so a copy is enough. Coverage is back at the floors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- @mark1russell7/cue in .: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/access: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/archive: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/better-auth: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/bundle-assistant: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/bundle-dev: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/bundle-mcp: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/claude-cli: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/algebra in packages/client: ^0.7.1, lockfile -> 0.7.3
- @mark1russell7/coeval in packages/client: ^0.6.3 -> ^0.7.0, lockfile -> 0.7.0
- @mark1russell7/service in packages/client: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/client: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-cli: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-collections: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-cue: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-cue: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-dag: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-docker: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-fs: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-git: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-lib: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-mcp: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/client-mcp: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/client-mongo: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-node: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-playground: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-pnpm: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-procedure: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-s3: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/client-server: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/client-server: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-shell: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-snapshot: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/splay in packages/client-splay: ^0.1.0 -> ^0.2.0, lockfile -> 0.2.0
- @mark1russell7/cue in packages/client-splay: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/docker-sqlite in packages/client-sqlite: ^0.1.0 -> ^0.2.0, lockfile -> 0.2.0
- @mark1russell7/cue in packages/client-sqlite: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/client-store: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/client-store: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-vite: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/client-vitest: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/coeval in packages/compiler: ^0.6.3 -> ^0.7.0, lockfile -> 0.7.0
- @mark1russell7/cue in packages/compiler: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/documentation: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/env: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/exif: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/geo: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/gh: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/http: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/ics: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/impl-mcp-dev: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/impl-mcp-dev: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/ios-backup: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/json: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/llm: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/llm: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/mail: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/mark: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/mark: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/mcp: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/notify: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/npm: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/pdf: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/privacy-scan: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/restic: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/schedule: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/service in packages/schedule: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/service in packages/server: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/server: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/signaldb: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/site: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/site-pages in packages/site: ^0.1.3, lockfile -> 0.1.5
- @mark1russell7/service in packages/systems: ^0.5.8, lockfile -> 0.5.10
- @mark1russell7/cue in packages/systems: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/tailscale: ^1.0.0, lockfile -> 1.0.2
- @mark1russell7/cue in packages/weather: ^1.0.0, lockfile -> 1.0.2
- pnpm-workspace.yaml: @mark1russell7/*, @procedures/* in minimumReleaseAgeExclude
chore(deps): release train update of 7 packages
The conflicts came from the squash of #181; the branch side wins (it
holds #181's head). The ics README keeps the tzid text of #196. The
PATCH changeset of #181 is gone: 0.28.1 shipped it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mark1russell7
mark1russell7 marked this pull request as ready for review October 25, 2026 17:03
@mark1russell7
mark1russell7 merged commit fd4794d into client/audit2-security Oct 25, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant