Skip to content

chore: sync main to dev#9479

Open
github-actions[bot] wants to merge 3 commits into
devfrom
chore/sync
Open

chore: sync main to dev#9479
github-actions[bot] wants to merge 3 commits into
devfrom
chore/sync

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

👑 An automated PR

alejandro-jimenez-dcl and others added 3 commits July 24, 2026 11:27
* fix: guard GltfContainer dereference against destroyed Root (#9452)

A stale StreamableLoadingResult could still reference a GltfContainerAsset
whose Root GameObject was already destroyed by GltfContainerAsset.Dispose
(drained by cache Unload). Re-dereferencing it invoked SetActive/SetParent on
the dead Root, surfacing as a NullReferenceException in IL2CPP
(ResetGltfContainerSystem -> DereferenceFinalOperation, Sentry UNITY-EXPLORER-P83).

Guard the single choke point every dereference path funnels through: skip when
asset.Root compares null (Unity destroyed-object check) before touching cache
state, so the crash is avoided and a dead instance is never re-pooled.

Add unit coverage for the pooled-live and destroyed-Root cases.

* log: repro the issue

* Refactor Dereference method in GltfContainerAssetsCache

Removed stale promise handling and associated logging from Dereference method.

Signed-off-by: alejandro-jimenez-dcl <alejandro.jimenez@decentraland.org>

* fix: restore destroyed-Root guard without repro logging

Re-add the asset.Root null guard in Dereference so a stale promise result
referencing an already-destroyed GameObject skips re-pooling, keeping only
the early return without the temporary repro logging.

---------

Signed-off-by: alejandro-jimenez-dcl <alejandro.jimenez@decentraland.org>
(cherry picked from commit 481ff99)
…3/004/005/008/019/028) (#9466)

* fix(sec-019): deny-by-default allowlist for deep-link params

Replace the copy-every-query-param behavior in ProcessDeepLinkParameters
with a shared deny-by-default allowlist (DeepLinkAllowlist). Only realm,
position, community, signin, authRequestId, force-open-backpack survive;
attacker-controllable flags (creator-hub-bin-path, launch-cdp-monitor-on-start,
local-scene, comms-adapter, ...) are dropped. Closes the SEC-019 arg-injection
root shared by the cold-start argv and runtime bridge paths.

SEC-020: local-scene is dropped by default, but re-permitted when the deep
link's realm is a loopback host (Uri.IsLoopback) so the legitimate local-scene
-development deep link keeps working while a remote-realm attacker link cannot
enable LSD.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sec-005): pin creator-hub binary to install path, drop app-arg override

* fix(sec-008/028): http(s)-only external-URL scheme policy

Add ExternalUrlPolicy as the single http(s) predicate for the client and
enforce it at the shared external-URL sink (UnityAppWebBrowser) so no caller
can hand a custom-scheme URL (decentraland://, smb://, file://, mailto://,
app-protocol) to the OS handler. Blocks SEC-028 launcher re-invocation and
SEC-008 NTLM/local-file abuse.

IsWebScheme validates the scheme by prefix without allocating a Uri; the
trust-cache path keeps using the already-parsed Uri via TryGetTrustKey.
Unifies the scattered http(s) URL checks (RealmLaunchSettings.IsRealmAValidUrl,
RealmUrls.CustomRealmAsync) onto this single function.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sec-008): reject non-web schemes at external-url prompt construction

* fix(sec-008): key external-url trust cache on (scheme, host); never cache empty host

* fix(sec-003): changeRealm prompt always requires explicit approval

Remove the empty-message auto-approve: RequestChangeRealm always renders the
destination (default confirmation text when no message) and WaitForCloseIntentAsync
always waits for an explicit Continue/Cancel/Close click. A scene can no longer
switch realm silently by passing an empty message.

Harden the consent display (SEC-003 #3): disable rich-text on the message/realm
TMP fields so an attacker-controlled string cannot inject TMP markup into the
prompt, and show the destination host (authority) with any misleading path/query
stripped, so the user consents to the real destination.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sec-004): host-suffix realm validation instead of substring match

* fix(sec-004): route runtime realm deep links through the consent prompt

A realm deep link on a running client now shows the ChangeRealm consent
prompt (Cancel does not switch). The prompt callback and Params carry the
target parcel as a typed Vector2Int? — a deep link with a position teleports
via ChatTeleporter.TeleportToRealmAsync(realm, position) directly (works for
URL realms), instead of stringifying the position into the realm and
round-tripping it through the /goto text command. Realm-only changes keep the
existing chat-command route.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(sec-deeplink): resolve net-new nullability warnings + document allowlist

Nullability (warnings introduced by this branch):
- ExternalUrlPromptController.Params.Uri is genuinely nullable (null for a
  non-web URL) -> declare Uri? and capture a non-null local in the consumer;
  clears CS8601 + the "always true/false" guards.
- Drop the redundant ?. on the non-nullable changeRealmCallback field.
- ChangeRealmPromptPlugin serialized field -> = null! (Unity-serialized).

DeepLinkAllowlist: document the deny-by-default rationale and add a per-arg
comment explaining why each permitted key is safe (navigation/share/login
intents gated by consent, a matching login token, or a plain coordinate);
keep PERMITTED_KEYS private behind IsPermitted.

Remaining warnings in these files are pre-existing framework/lifecycle
patterns (viewInstance nullability, resultCallback lifecycle) left as-is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix compiler warnings

* Always print dropped app args

* chore(sec-005): remove creator-hub-bin-path arg; editor-only path override

creator-hub-bin-path was the SEC-005 RCE vector (an attacker-reachable app-arg /
deep-link param that set the executable CreatorHubBrowser launches). It is already
neutralized by pinning the browser to the default install path, so remove the arg
entirely: the AppArgsFlags const, the Debug Settings drawer plumbing, and the docs
entry. No runtime code reads an externally supplied executable path anymore.

Restore the developer's ability to point CDP DevTools at a non-default Creator Hub
build via an editor-only override stored in EditorPrefs
(CreatorHubBrowser.BinPathOverride), assigned through the Debug Settings drawer. It
is read only under #if UNITY_EDITOR and never comes from app-args or deep links, so
player builds can launch only the pinned default path.

- CreatorHubBrowser: ResolveBinPath() returns the EditorPrefs override in the Editor,
  else DEFAULT_CREATOR_HUB_BIN_PATH.
- DebugSettingsDrawer: path field / Browse / "Use Default Path" now read-write
  EditorPrefs instead of injecting a --creator-hub-bin-path app-arg.
- AppArgsTests: SEC-005 regression now asserts the literal key is dropped by
  deny-by-default (the const no longer exists).
- docs/app-arguments.md: drop the creator-hub-bin-path entry.

Verified: Unity 6000.4.0f1 batch EditMode compile clean (0 error CS), AppArgs tests 10/10.

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

* feat(sec-005): allow creator-hub-bin-path via app-args only

Restore the creator-hub-bin-path override (removed in the prior commit). With
the SEC-019 deny-by-default deep-link allowlist in place, the param can only
reach appParameters through the trusted command-line channel — a decentraland://
link carrying it is dropped (asserted by DeepLinkDropsInternalFlags). The RCE
vector is therefore closed by the allowlist, so exposing the app-arg override
again is safe.

- AppArgsFlags: re-add CREATOR_HUB_BIN_PATH const.
- CreatorHubBrowser: read the creator-hub-bin-path app-arg via IAppArgs, else
  the pinned DEFAULT_CREATOR_HUB_BIN_PATH.
- ChromeDevToolHandler.New / BootstrapContainer: thread IAppArgs back in.
- DebugSettingsDrawer: editor path field writes the app-arg (appParameters)
  again instead of EditorPrefs; widen two locals to string?.
- AppArgsTests: DeepLinkDropsInternalFlags asserts the key stays dropped from
  deep links (the "app-args only" guarantee).
- docs/app-arguments.md: restore the entry, noting it is app-args-only.

Security note: this makes the SEC-019 allowlist the sole barrier keeping
creator-hub-bin-path off the untrusted channel (A2's binary pin is gone). That
holds only while the launcher never promotes received deep-link params to
trusted --flag args (cross-repo invariant; the CH app-args migration spec's
launcher guard test locks it).

Verified: Rider solution analysis reports 0 errors on all changed files. Unity
batch EditMode was not re-run this iteration (the Editor held the project lock);
the only test change swaps a literal for the identical-valued const.

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

* feat(sec-005): resolve Creator Hub path at runtime; drop the app-arg

Remove the creator-hub-bin-path app-arg (restored in the previous commit) and
resolve the Creator Hub executable at the point of use instead. The CDP bridge is
the only consumer, so CreatorHubBrowser.OpenUrl now resolves lazily:

  1. a path the developer previously selected (DCLPlayerPrefs), if it still exists;
  2. else the pinned default install path;
  3. else prompt the developer to locate it (FileBrowser PRO - Editor + Win/Mac/Linux
     standalone) and remember the choice in DCLPlayerPrefs.

No attacker-reachable input feeds the exec sink: the path is either the known
install location or a local file the developer explicitly picks, and the prompt
fires only when DevTools actually needs to launch Creator Hub.

- AppArgsFlags: drop CREATOR_HUB_BIN_PATH.
- CreatorHubBrowser: PlayerPrefs -> default -> FileBrowser prompt; no IAppArgs.
- ChromeDevToolHandler / BootstrapContainer: drop the IAppArgs plumbing.
- DebugSettingsDrawer: drop the path field; keep the CDP toggle + install status.
- DCLPrefKeys: add CreatorHub.BinPath.
- DCL.Network.asmdef: reference filebrowserpro.runtime (the assembly CreatorHubBrowser
  compiles into, via the DCL.WebRequests asmref).
- AppArgsTests: assert creator-hub-bin-path stays dropped from deep links.
- docs/app-arguments.md: remove the entry.

Verified: Unity 6000.4.0f1 batch EditMode - compile clean (0 error CS), AppArgs tests pass.

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

* feat(sec-019): permit SDK/Creator Hub dev deep-link params for a loopback realm

Generalize the local-scene loopback gate into a second allowlist tier: the
local-development params Creator Hub and sdk-commands attach to their preview deep
links are permitted only when the target realm is loopback (127.0.0.1 / localhost
/ [::1]). A remote-realm deep link from a web page cannot enable them, while a
legitimate local-dev launch (which always targets loopback) works.

Loopback-permitted set: local-scene, dclenv, hub, skip-auth-screen,
landscape-terrain-enabled, multi-instance. Each is individually low-harm (env
enum, analytics tag, cosmetic toggle, instance count, or a screen skip that still
forces auth when no valid identity is cached); the loopback gate confines them to
the dev context. The SEC-005 exec params (creator-hub-bin-path,
launch-cdp-monitor-on-start) and the attacker-infrastructure params stay dropped
for every realm.

- DeepLinkAllowlist: add LOOPBACK_REALM_PERMITTED_KEYS + IsPermittedForLoopbackRealm;
  document the three tiers (always / loopback-only / never).
- ApplicationParametersParser.ProcessDeepLinkParameters: two-tier resolution
  (base keys -> normalize realm -> loopback-gated dev keys), replacing the
  local-scene-only special case.
- AppArgsTests: dev params kept for a loopback realm, dropped for a remote realm,
  and exec/infra params dropped even for a loopback realm.

SEC-019/020 policy expansion (product decision).

Verified: Unity 6000.4.0f1 batch EditMode - 0 compile errors, AppArgs tests 13/13.

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

* fix(sec-004): strip userinfo from consent-prompt host; drop stale spawnpoint doc

Addresses the decentraland-bot review of PR #9466:

- P1 (security): ChangeRealmPromptController.DestinationHostFor now skips past any
  userinfo ('@') so the real host after the last '@' is shown on the consent
  prompt. Previously a realm like https://decentraland.org@evil.com displayed
  "decentraland.org@evil.com" while actually connecting to evil.com — a spoof.
  Matches the '@' handling already in ChatEnvironmentValidator.HostHasSuffix.
- P2 (docs): DeepLinkAllowlist XML doc no longer lists 'spawnpoint' as permitted —
  it isn't in PERMITTED_KEYS and no SPAWN_POINT const exists on this branch (the
  dev spawn-points feature #9369 was dropped when the branch was made SEC-only).

Verified: Unity 6000.4.0f1 batch EditMode - 0 compile errors, AppArgs tests 13/13.

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

* fix(sec-004): close HostHasSuffix colon-before-@ host spoof + review cleanups

Addresses the decentraland-bot re-review of PR #9466 (1 P1 + 5 P2):

- P1 (security): HostHasSuffix broke its scan on ':' before reaching any '@', so
  https://decentraland.org:1234@evil.com extracted host "decentraland.org" and passed
  the suffix check while the real host is evil.com. Fix: don't break on ':'; reject on
  '@' (checked before any ':'); strip the port after the loop. + regression cases
  (colon-before-@, plain userinfo, legit host:port).
- DestinationHostFor: made internal + new ChangeRealmPromptDestinationHostShould (7 cases:
  userinfo/port/query/fragment/no-scheme). UI assembly exposes internals to DCL.EditMode.Tests.
- DeepLinkHandleImplementation: thread the cancellation token through SwitchToMainThread
  and ShowAsync.
- DeepLinkAllowlist: remove the // ReSharper disable CheckNamespace suppression (CLAUDE.md
  §11; the namespace compiles fine — matches siblings).
- ChangeRealmPromptController.Params: collapse the dual constructors into one with a default;
  simplify the caller.
- DynamicWorldContainer: TODO documenting the position-teleport result/token gap.

Verified: Unity 6000.4.0f1 batch EditMode - 0 compile errors, 30/30 tests pass (AppArgs 13,
ChatEnvironmentValidatorShould 10, ChangeRealmPromptDestinationHostShould 7).

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@github-actions
github-actions Bot requested review from a team as code owners July 24, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants