Skip to content

v6.10.0 — MCP security, six headless demo scenes, and a long tail of silent failures

Choose a tag to compare

@NeoXider NeoXider released this 29 Jul 13:32
· 99 commits to main since this release

Acts on fresh audits of all five packages.

⚠️ Security

The in-game MCP server accepted cross-origin requests. Binding to 127.0.0.1 stops network access but not the user's own browser: with Content-Type: text/plain a POST is a "simple" CORS request and skips preflight, so any open web page could call tools/call execute_lua or manage_mods — and DNS rebinding makes the request same-origin, exposing replies including screenshot.

Requests are now screened before routing (IsLocalHostOrigin → JSON Content-Type) and authenticated with a bearer token, generated per run or pinned via COREAI_MCP_TOKEN. The server remains off by default and is in no shipped scene.

Migration: existing clients must send Authorization: Bearer <token>. The token is printed to the game console with a ready-to-paste command; set COREAI_MCP_TOKEN once for a stable config.

Fixed

  • Six published demo scenes ran mods headlessInstance.new produced nothing in them. CoreAiHubDemo, LiveMechanicsDemo, LiveMechanicsModsChatDemo, WaveAutoBattlerModsDemo, MiniRpgModsDemo and ModdableUnitsDemo now each carry a wired RbxWorldHost.
  • Editing a mod in the Hub froze the game.
  • LLMManager.LoadFromDisk() wiped the LLMUnity model registry in the Editor — a "rescan" that erased the user's registered models, permanently once anything saved afterwards.
  • A ChainReset past the first line no longer verifies an audit log as intact. Truncating the tail and appending a forged restart used to report Ok.

Failures that were silent by construction

  • A library timeout surfaced as "cancelled", so it read as if the user pressed Stop and the timeout branch never ran.
  • An empty streaming response counted as success while vanishing from history and traces.
  • MutateAsync destroyed a role's memory when the load failed rather than being absent.
  • game_config update reported success when the store rejected the write.
  • WebGL: Task.Delay in the endpoint drain loop never resumed and wedged activation forever; seven unguarded SwitchToThreadPool calls hung tool turns; an unclamped transcript entry could crash the player.

Added

GameLogFilter — a real runtime logging API over a runtime copy of the authored ScriptableObject, so filters change in a player without mutating the asset. GameLogFeature.All now actually includes every category (it silently omitted Metrics), the no-asset default no longer ignores categories or mutes everything below Warning, and the static fallback used by ~15 files is finally under the same filter. First tests that prove filtering drops messages, rather than only testing the predicate.

Verification

EditMode: 2539 tests, 0 failed. The demo-scene smoke test passes after the scene fix. Remaining PlayMode failures are a local LM Studio that cannot load its model, plus one pre-existing TargetCube assertion that reproduces identically on a clean HEAD.