Repository navigation
security: the HTTP server's default CORS answer admits every origin for credentialed requests (detail withheld under the disclosure ruling) #24738
Description
Filing gate ③ a task the maintainer set, in the repo:hotcrm seat 2 chat on 2026-10-20 (verbatim): 「立卡:CORS 默认允许任意来源,带凭据时回显请求的来源」. Filed by the repo:hotcrm seat 2 (os-support-ai, session session_01KqkTQNLcxVc588eZpJmp1r, seat post objectstack-ai/hotcrm#2180) after a source read for the maintainer's question on gateway and WAF needs. ⛔ Not a claim. Domain, type and grade are triage's.
Disclosure: this is an access-control finding. Under the maintainer's disclosure ruling (2026-08-18, recorded on #9387, 5323310017), this card records the defect's existence, where it lives and the governing text only. No reproduction or exploit path is published. The detail stays with the filing seat and the maintainer.
Reader (who acts): objectstack triage routes it to the owner of packages/plugins/plugin-hono-server.
What is wrong (read from source on objectstack main 9b2953d62; not measured)
packages/plugins/plugin-hono-server/src/hono-plugin.ts, the CORS middleware (about lines 358–426):- With no
cors.originsoption and noOS_CORS_ORIGIN, the configured origin is'*'. credentialsdefaults totrue.- In that combination, the origin handler returns whatever origin the request carries.
- With no
- The net default is that every origin is allowed for credentialed cross-origin requests. The option's own TSDoc (about line 75) says "Enabled by default with origin '*'", and
content/docs/deployment/environment-variables.mdx:125-128documents the same defaults (*, credentialstrue). - The deployment docs never tell an operator that this is the default they must change.
content/docs/deployment/self-hosting.mdxandproduction-readiness.mdxlist no CORS step.
Governing text
docs/HARDENING.md§ CORS: "Do not useorigin: '*'withcredentials: true", and its go-live checklist: "CORS origin list is explicit, not*". The runtime's default is exactly the combination the file forbids. The same section opens "CORS is intentionally not opinionated by the runtime", which the code above contradicts.- The runtime's own security defaults lean the other way: deny-all CSP and
Cross-Origin-Resource-Policy: same-origin(packages/runtime/src/security/security-headers.ts).
Expected (proposed; triage owns it)
- The default admits no foreign origin for credentialed requests: the host's own origin and the configured trusted origins only. Localhost stays admitted in dev only, if at all.
OS_CORS_ORIGIN='*'together with credentials is refused loudly at boot, or downgraded to non-credentialed, rather than silently turned into "reflect anything".HARDENING.mdand the deployment pages state the default as it then is, plus the one variable an operator sets.
Dedupe (objectstack issues, all states, semantic search)
- "CORS default origin wildcard with credentials reflects any request origin hono-plugin OS_CORS_ORIGIN": 0 hits.
- "CORS allow any origin credentials": 0 hits. "CORS": 0 hits.
- Control: "allowedIpRanges network gating ADR-0069 D5" returns 3 hits (security: a session the ADR-0069 auth gate holds can still be served by the storage route family (detail withheld under the disclosure ruling) #24366, core: put the exact approvals act path on the ADR-0069 auth-gate allow-list, token-only as ADR-0043 sets it and as the self-hosted mount already serves it (segment 3 of ruling A on #22438) #22577, owd-save-gate: the ADR-0090 D11 authoring gate never runs on any host-config deployment (keyed on environmentId, not authoringChannel) #7674), so the search reaches the security corpus.
Dedupe words: CORS reflect origin credentials default; OS_CORS_ORIGIN wildcard; hono-plugin cors default; HARDENING CORS contradiction.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 20, 2026
Triage: p1 ·
bug·security· lanedomain:cli·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-20T04:59ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on
origin/main580fd4ed3c. Disclosure: this grade adds nothing beyond what the card already holds, ⛔ no reproduction or exploit path (RUNNER rule 2, #9387).Lane.
packages/plugins/plugin-hono-serverisdomain:cli(SKILL.md:166).Why p1. The card names the shipped default and the governing text it contradicts (
docs/HARDENING.md§ CORS). It reaches every deployment that sets no origin list. ③, maintainer-directed.18.0. This is a default that ships, and changing it later is a behaviour change for deployments that rely on it. Whether it goes into 18.0.0 is the maintainer's call, and it is on the maintainer list.
Shape: as the card proposes: a default with no foreign credentialed origin, a loud refusal for
*plus credentials, and docs that state the default. The docs half touches the sameHARDENING.mdas #24740, so land them serially.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Claim: PM loop round 4 ·
domain:cliseat 2 · p1 ·security(the shipped CORS default contradictsdocs/HARDENING.md§ CORS) · serial (batch1) · 2026-10-20T05:29ZSession:
session_01LmjU2x1faLZ39DVTFyVca6Account:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24738-cors-default-no-foreign-credentialed-originWorktree:
objectstack-issue-24738Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)Disclosure: under the maintainer's ruling on #9387 (
5323310017), this claim, the PR and every comment state the default and its fix at the card's level only. No reproduction steps and no exploit path go on the public side. Tests that pin the refusal are the fix's own evidence, and they stay.File surface (read on
origin/main795ff708d; line numbers move; stop on a breach and explain it in the report):packages/plugins/plugin-hono-server/src/hono-plugin.ts: the CORS middleware (about:359–:426) and thecorsoption's TSDoc (about:74–:80). Alsoadapter.tswhereHonoCorsOptionsdocuments the default, the package's tests and itsREADME.md.packages/cli/src/commands/serve.ts, only if the host's own origin and the configured trusted origins have to be handed to the transport.servealready resolves them for auth (about:4186–:4257). This is the one cross-package seam the card allows, and the dev measures whether it is needed.docs/HARDENING.md§ CORS only;content/docs/deployment/environment-variables.mdx(about:125–:128); and one CORS step incontent/docs/deployment/self-hosting.mdxandproduction-readiness.mdx.6283755806and the card. The default admits no foreign origin for credentialed requests: only the host's own origin and the configured trusted origins (localhost in dev only, if at all).*together with credentials is refused loudly at boot, or made non-credentialed, and is never silently turned into reflecting the request's origin. The docs state the default as it then is, plus the one variable an operator sets.packages/spec/**.CorsConfigSchema(shared/http.zod.ts) is spec's, and the futureserver.corsadmission is the 2026-08-04 ruling's, not this card's.docs/HARDENING.md§ Rate limiting and § Trust the proxy, which are docs: HARDENING.md and production-readiness.mdx still describe rate limiting as adapter-wired and off, and never name server.security.rateLimit or trustProxy #24740's.content/docs/deployment/cli.mdx, which PR feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681 touches.Container & model:
M,mode:subagent,model: default tierfor the build (dispatch-gates.mjs --tier: "no path-derived mandate"). The narrowing face owesCONTRACT_REVIEW_TIER(reason: the card narrows a shipped HTTP admission default;contract-review.md).Clause-②: no (narrowing)
Basis for the Clause-② line: the transport stops admitting, for credentialed requests, origins it admitted before, and refuses a configuration it accepted before. That narrows a shipped default. No published schema widens, and spec is untouched. It owes one
CONTRACT_REVIEW_TIERreview of record before the queue, and it stays in this lane.Responsibility: this lane's transport plugin (
packages/plugins/plugin-hono-server) ships the default. No platform path covers it: auth's trusted origins guard auth's own routes, not the transport's CORS answer, and the dev measures that. It reaches every deployment that sets no origin list.Landing: held, beyond the review of record, on the maintainer's word on whether it enters 18.0.0 (triage
6283755806: "Whether it goes into 18.0.0 is the maintainer's call"). The build does not wait on it.Thread-read: 6283755806
Serial constraints cleared:
packages/plugins/plugin-hono-server/**,packages/cli/src/commands/serve.ts,docs/HARDENING.md, or the three deployment pages named above. All 11 open PRs were read in this act; PR feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681 touchescontent/docs/deployment/cli.mdx, which is held off.docs/HARDENING.md. Triage asks the two to land serially: whichever lands second mergesmain.wall-environment-metadata-refusal.dogfood.test.tsread a refusedpublish-drafts(200,success: false,list-view-object-outside-closure) as a write, so they measure nothing at that door #24725, is in the merge queue (PR fix(dogfood): the wall CONTROL cases' packages declare the CRM dependency and their publish lines read the receipt #24777) on a disjoint file. Seat 1's rest: a NOT NULL refusal on a storage.notNull field without required names the column key, not the field label — a user clearing Sales Price is told "unit_price is required" #24715 (PR fix(types,rest): a /data write's NOT NULL refusal names the field by its label #24759,packages/typesand the/dataerror path) is disjoint.pm:on-holdcards'Restart-touch:lines (15 cards, 1 line:scripts/test-shard-timings.json) have no hit.objectstack-fleet commentedon Oct 20, 2026
Maintainer ruling recorded · 18.0.0 ·
domain:cliseat 2 (#22648) ·os-justin· sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T06:28ZTriage
6283755806left this one open: "Whether it goes into 18.0.0 is the maintainer's call". The seat put it to the maintainer in this session's chat, and the maintainer answered, verbatim: 「24738 可以进」.mainfor 18.0.0. The landing hold the claim6284118564named for this question is lifted.CONTRACT_REVIEW_TIERreview of record for the narrowing face;5323310017) still governs every artifact of this card.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Ruled: into 18.0 (
target:v18) · recorded by the triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-20T07:03ZThe maintainer, in this seat's session, verbatim: 「进 18.0 同意你的清单」. That answers the triage seat's 18.0 list:
What it binds. 18.0.0 ships the corrected CORS default, so the default change lands in the major, as the card's Expected proposes. That covers the default, the loud refusal of
*with credentials, and the docs. It is claimed. ItsHARDENING.mdhalf stays serial with #24740.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 24738, "status": "done", "branch": "claude/issue-24738-cors-default-no-foreign-credentialed-origin", "pr": "https://github.com/objectstack-ai/objectstack/pull/24806", "session": "session_01LmjU2x1faLZ39DVTFyVca6 (subagent: the parent's, as the commits' Claude-Session trailer stamps it)", "premise_still_valid": true, "summary": "Zone 2 assumption 1 is confirmed on main 795ff708d. With no cors.origins and no OS_CORS_ORIGIN, the transport's CORS answer admitted every origin with credentials, and '*' with credentials booted: 8 of the 12 new pins went red on main's source. HonoServerPlugin now admits no cross-origin caller when no list is configured. Loopback origins are admitted on a development boot only (isDevelopmentBoot, NODE_ENV exactly development). A '*' entry while credentials are on is refused in init(), so the boot fails naming OS_CORS_ORIGIN and OS_CORS_CREDENTIALS (assumption 4: loud refusal, precedent plugin-dev's assertNotProduction, ADR-0115 D6). Assumption 2: no serve.ts seam was needed. Same-origin requests are outside CORS, the configured list is the one the transport already reads, and no second copy of auth's trusted-origin rules was added. Whether OS_TRUSTED_ORIGINS should also feed CORS is the one open question. Assumption 3, consumers measured: three repo tests leaned on the old default and were fixed (a runtime metrics pin configured '*' with credentials; two http-conformance door-parity pins compared CORS headers by accident). No example and no shipped code depended on it, and objectui's console is same-origin. The docs (HARDENING.md section CORS, environment-variables, self-hosting, production-readiness, the README) state the default and the one variable. The changeset is plugin-hono-server minor, BREAKING narrowing, Clause-2 no (narrowing), ADR-0087 not-required (no-migration-prescription). Landing stays held on the CONTRACT_REVIEW_TIER review and on the maintainer's 18.0.0 call. Worktree removed after the PR opened.", "tests": "RED LEG, main's own source (b1bb0d25c = 795ff708d plus the test file only): pnpm --filter @objectstack/plugin-hono-server exec vitest run --maxWorkers=2 src/cors-default-admission.test.ts gave 'Tests 8 failed | 4 passed (12)'. The failures were 'expected https://other.example to be null', 'expected http://localhost:5173 to be null' and 'expected null to be an instance of Error'. The 4 that passed are the preservation pins. GREEN at f7cb52d15: the same file 12/12. pnpm --filter @objectstack/plugin-hono-server test: 'Test Files 35 passed (35) / Tests 434 passed (434)'. pnpm --filter @objectstack/plugin-hono-server typecheck: exit 0, with 'check:test-typecheck: OK', and tsc -p tsconfig.test.json --listFiles counts the new file once. pnpm --filter @objectstack/http-conformance exec vitest run --maxWorkers=2: 'Test Files 18 passed (18) / Tests 228 passed (228)'. runtime http-metrics-inbound-coverage.hono.integration + dispatcher-plugin.rate-limit.integration: 'Test Files 2 passed / Tests 35 passed'. Consumer runs through the rebuilt dist on the tree committed as 8c038d76d: the 12 runtime files that boot HonoServerPlugin with CORS on gave 'Tests 123 passed'; the 6 client files gave 'Tests 30 passed'. Before its fix, the runtime metrics pin gave 'Plugin init failed: com.objectstack.server.hono' and 'Tests 1 failed | 26 passed (27)'; this also shows the refusal fails a real kernel boot. Before theirs, the two http-conformance pins failed on an extra 'access-control-allow-origin: *' header from the hosted door. No ablation: the red leg is main's own source, run before the fix was written; the tests import ./hono-plugin from src, so there is no dist path to stale.", "gates": "Local subset at f7cb52d15: node scripts/pm/dispatch-gates.mjs --commands derived 98 families. All 98 ran with the exit code captured before any pipe, and every one is 0. --ran reconciliation (exit 0): 'Run reconciliation -- 98 derived, 98 run, 0 NOT-MEASURED, 0 UNRUN'. Among them: check:adr-0087-registration --base origin/main ('1 declared-breaking changeset(s), each carrying an ADR-0087 disposition'), check:changeset-no-major, check:doc-anchors, check:doc-authoring, lint check:doc-security-posture, check:nul-bytes, check:published-files, check:dual-build-cjs-loads ('111 published require entry point(s) across 69 package(s) load'), check:type-check-coverage and check:type-check-debt ('re-measure: OK -- 26 raw tsc error(s) total, none above its recorded number'). The first round at 8330356b4 had three exit-3 PREREQUISITE NOT MET results (lint, formula and client-react unbuilt). They were rebuilt and re-run to 0, never counted as failures. pnpm lint (eslint . --no-inline-config) at f7cb52d15: exit 0. CI check-runs on f7cb52d15 at report time, not waited on: completed success are Check Changeset, Check PR Size, Governed Surface Queue Guard, Dogfood Regression Gate, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Spec property liveness, The card this PR closes must claim this branch, Check Documentation Links and Flag docs affected by code changes. in_progress are Build Core, Build Docs, Test Core (1/6..6/6), Type Check · workspace/source gates/consumer gates/debt ledger, Lint · ESLint, Lint · docs & code guards, Lint · repo & tooling gates, Lint · CI, release & engine gates, Lint · scoped · query-options erasure and Lint · scoped · slot lookup & corpus.", "mcp_calls": "0 -- no MCP GitHub tool was called (reads went through gh api GET; writes through the fleet-write relay)", "api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches; run 39385044244 for the first) executing 3 REST writes as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft #24806, body read back byte-identical, 10250 bytes); POST /repos/objectstack-ai/objectstack/issues/24806/assignees (os-justin, read back); POST /repos/objectstack-ai/objectstack/issues/24738/comments (this report). Outside REST: git push of the branch. No label written (none named by the dispatch; skip-changeset does not apply to a published-package change with its changeset).", "open_questions": [ { "question": "Should the transport's no-list CORS default ALSO admit the origins in OS_TRUSTED_ORIGINS (auth's callback/CSRF list), which three doc lines had called the CORS allow-list? Shipped: no. CORS admits only cors.origins / OS_CORS_ORIGIN, and the docs now say the two lists are separate (cli.mdx's line is held off, see findings).", "options": [ "A (shipped) Keep them separate. Business need: measured, no in-repo consumer is cross-origin (the Console is same-origin, objectui dev goes through its /api proxy with VITE_SERVER_URL empty, the showcase e2e is same-origin, examples mount no HTTP). The documented self-hosting topology is same-origin, so no documented setup relied on OS_TRUSTED_ORIGINS for CORS. External cross-origin front-ends are unmeasured. Long-term: one variable per policy. AI-error: one rule, one variable, nothing inherited from a second subsystem. Startup: no new seam or option. Cost: a deployment whose cross-origin front-end set only OS_TRUSTED_ORIGINS loses CORS admission on upgrade, quietly at boot and visibly in the browser; the changeset and HARDENING state the operator step. Effort: none.", "B Admit the explicit OS_TRUSTED_ORIGINS entries as well. Business need: rescues the unmeasured deployment in A. Long-term: either a second reader of auth's variable in the transport, or a new HonoCorsOptions field plus a serve.ts hand-off; it couples CSRF trust to credentialed read access. AI-error: the CORS answer then depends on two variables owned by two subsystems. Startup: a new seam with no measured pull. Effort: small.", "C Admit serve's full trusted-origin resolution (the base origin, the OS_PREVIEW_BASE_DOMAINS wildcards, the OS_ROOT_DOMAIN wildcard and dev localhost). Business need: as B. Long-term: it imports auth's preview and per-project wildcards into credentialed CORS, which on multi-project hosting admits sibling projects' origins. The list is also computed inside serve's auth branch, after the transport is constructed, so serve.ts needs restructuring. AI-error: the worst of the three. Startup: the widest. Effort: medium." ], "recommendation": "A. It is the only option that meets the triage shape (no unconfigured foreign credentialed origin) without importing auth's CSRF wildcards into CORS. It needs no new seam. The one case B and C rescue is unmeasured, and the operator step is already in the changeset and HARDENING. Answering A needs no further code." } ], "out_of_scope_findings": [ "class: b · reach: exception: security · Seam: spec:none (transport option; consumer: none in spec) to runtime: packages/adapters/hono/src/index.ts createHonoApp CORS block (about :607-:680) · @objectstack/hono's createHonoApp keeps the old default. With no origin list every origin is admitted for credentialed requests, and '*' with credentials is accepted. Contract: docs/HARDENING.md section CORS, 'Do not use origin: * with credentials: true'. Measured on this PR's own tree before the test fix: the two http-conformance door-parity pins (hono-approvals-act, hono-webhooks-redeliver) went red because the hosted door still answers access-control-allow-origin '*' with credentials where HonoServerPlugin now answers none. It is the same family as #24738, so fold it into the family's closure rather than a point card. The adapter already imports createOriginMatcher and the CORS header defaults from plugin-hono-server, so it can share this PR's rule. Not widened into this PR, per the dispatch. · dedupe words: createHonoApp CORS default; @objectstack/hono cors origin credentials; hosted door CORS parity; adapter OS_CORS_ORIGIN default star", "class: b · reach: exception: security · Seam: spec:none (consumer: none) to runtime: packages/plugins/plugin-hono-server/src/pattern-matcher.ts matchOriginPattern / createOriginMatcher (shared with cloud's serverless preflight short-circuit) · A configured origin list admits loopback origins in every mode, production included, with credentials. Contract: the HARDENING go-live item 'CORS origin list is explicit' and the card's 'Localhost stays admitted in dev only'. Unchanged here: the card scopes that phrase to the default, and the matcher is shared with cloud. HARDENING's table now states it plainly. · dedupe words: matchOriginPattern localhost always allowed; CORS loopback explicit list production; isLocalhostOrigin bypass", "carrier: PR #24681 · content/docs/deployment/cli.mdx (about :523) still calls OS_TRUSTED_ORIGINS '(CORS)'; whichever of #24681 and #24806 lands second corrects it · noted, not filed", "carrier: 承接者:无 · CorsConfigSchema (packages/spec/src/shared/http.zod.ts) declares origins default '*' with credentials default false; the transport does not read it (spec lane, held off); it matters when server.cors is admitted under the 2026-08-04 ruling · in PR Acceptance notes only", "carrier: 承接者:无 · the boot refusal covers a literal '*' entry only; a degenerate host wildcard such as https://* is not refused · in PR Acceptance notes only", "carrier: 承接者:无 · content/docs/protocol/kernel/http-protocol.mdx section 'CORS Headers' opens 'ObjectStack sends CORS headers automatically' over an admitted-origin example, which now reads wider than the default. It is not in the write-once PR body; the seat may append to Acceptance notes: 'http-protocol.mdx CORS Headers shows a configured origin; with no list none is admitted' · noted, not filed", "carrier: 承接者:无 · NOT MEASURED: whether objectstack-ai/cloud composes HonoServerPlugin with the default CORS answer (cloud is not in this container); cloud's serverless preflight short-circuit imports createOriginMatcher, whose behaviour this diff does not change · noted, not filed" ], "line_budget": "441 changed lines (+391 / -50) over 12 files against the origin/main merge base, read from git diff --numstat origin/main...f7cb52d15; human-merge threshold 3000: under. No governed surface or skills/** path is touched (docs/HARDENING.md is not on the register).", "deviations": [ "Three files outside the claim's file surface: packages/runtime/src/http-metrics-inbound-coverage.hono.integration.test.ts, packages/qa/http-conformance/src/hono-approvals-act.conformance.test.ts and hono-webhooks-redeliver.conformance.test.ts. All three are tests in this repo that the new default broke, which the dispatch allows fixing here; each was measured red before its fix and green after.", "Attribution: commits carry the model-free trailer pair AGENTS.md prescribes (Claude-Session plus 'Co-authored-by: Claude'), not the harness reminder's model-named Co-Authored-By line. The PR body ends in AGENTS.md's session-URL footer, not the reminder's two-line block.", "Gate runner: two batches hit the 590 s foreground cap. The in-flight gate child (check:type-check-debt pid 28733 in round 1, check:query-options-erasure pid 15834 in the final round, each bounded by its own timeout 280) outlived its parent. Each was waited out with tail --pid, never killed by name, and re-run to a captured exit code.", "origin/main was merged twice before the PR opened (to 74f78159a, then 46bb5e3e5), both disjoint from the diff; types, rest, platform-objects, plugin-security and plugin-hono-server were rebuilt after the second. No merge after the PR opened.", "check:* gates ran outside the verify lock, as the lock rules say; every build and vitest run went through os-verify-lock.sh. No environment value was printed; presence was checked only with the non-printing form." ], "files_changed": [ ".changeset/24738-cors-default-no-cross-origin-caller.md", "content/docs/deployment/environment-variables.mdx", "content/docs/deployment/production-readiness.mdx", "content/docs/deployment/self-hosting.mdx", "docs/HARDENING.md", "packages/plugins/plugin-hono-server/README.md", "packages/plugins/plugin-hono-server/src/adapter.ts", "packages/plugins/plugin-hono-server/src/cors-default-admission.test.ts", "packages/plugins/plugin-hono-server/src/hono-plugin.ts", "packages/qa/http-conformance/src/hono-approvals-act.conformance.test.ts", "packages/qa/http-conformance/src/hono-webhooks-redeliver.conformance.test.ts", "packages/runtime/src/http-metrics-inbound-coverage.hono.integration.test.ts" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
ACCEPT → PR #24806 comment
6285885816·domain:cliseat 2 · sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T07:37Z · headf7cb52d15. The review of record is6285870503(CONTRACT_REVIEW_TIER, PASS). The same family's remaining locations are filed as #24809. Landing waits on three things: every check of the head, this lane's main-red #24780 (PR #24805 in the queue), and the maintainer's word on the openOS_TRUSTED_ORIGINSquestion.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Maintainer ruling recorded ·
OS_TRUSTED_ORIGINSand CORS ·domain:cliseat 2 (#22648) ·os-justin· sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T09:42ZThe dev's open question (report
6285567675) asked whether the transport's CORS answer should also admit the origins inOS_TRUSTED_ORIGINS. The seat put three options to the maintainer in this session's chat and recommended A, with one docs precision:OS_TRUSTED_ORIGINSentries;The maintainer answered, verbatim: 「同意」.
OS_CORS_ORIGIN/cors.origins.OS_TRUSTED_ORIGINSstays auth's list, for the CSRF origin check and the callback / redirect targets.auth-manager.tsmerges a non-*OS_CORS_ORIGINinto better-auth's trusted origins.OS_CORS_ORIGIN, and is then trusted by both.https://*.<OS_ROOT_DOMAIN>sibling projects that share a cookie domain.docs/HARDENING.mdand any deployment page that says a cross-origin front-end that signs in "belongs in both" lists will say instead thatOS_CORS_ORIGINalone suffices, because auth trusts it too.OS_TRUSTED_ORIGINSis for auth-only origins.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Landed: PR #24806 →
f7546a4de(Fixes #24738)domain:cliseat 2 ·os-justin· sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T10:49Zadded_to_merge_queue2026-10-20T10:17Z, merged 2026-10-20T10:48Z)origin/mainf7546a4deis on it, with a single parentbd6dab009(squash). 12 files, +394 / −50. Every file's blob equals the ACCEPTed headdbdd7fe6a'sgh-readonly-queue/main/*pr-24806*head remainscompletedby the PR'sFixes. In the stroke after this comment,pm:dispatchedcomes off6284118564→ report6285567675→ review of record6285870503(PASS onf7cb52d15) → ACCEPT6285885816;6284880389) and A on the open question (6288093770);6288540922(PASS ondbdd7fe6a) → ACCEPT addendum6288555182.HonoServerPlugin's CORS answer admits no cross-origin caller. Loopback origins are admitted on a development boot only.*with credentials is refused at boot.OS_CORS_ORIGINalone covers a cross-origin front-end that signs in.@objectstack/plugin-hono-serverships it asminor, BREAKING, in 18.0.@objectstack/hono'screateHonoApp, loopback beside a configured list, all-host patterns) — family closure, detail withheld under the disclosure ruling #24809 (no longer blocked by this card):createHonoApp's default, loopback beside a list, all-host patterns, and a*entry in auth's trusted set.docs/HARDENING.mdand now mergesmainover this landing.Generated by Claude Code