v1.1.2 — a WebSocket that trusted the wrong thing
godot-mcp-bridge 1.1.2 — a WebSocket that trusted the wrong thing
The bridge binds 127.0.0.1. That stops a remote host. It does not stop the
browser on the same machine, and it was never supposed to be relied on for that.
Any page you visited could drive your editor
A WebSocket handshake is not subject to the same-origin policy. Binding to
loopback keeps a remote attacker out, but a page open in your browser — any
page, while the editor happened to be running — could connect to
ws://127.0.0.1:6505 exactly as the addon does, and from there call any tool.
That includes writing files into the project and game_eval.
Browsers always send an Origin header on a WebSocket handshake and cannot be
told not to. Godot's WebSocketPeer never sends one. So the fix is one check:
refuse any handshake carrying Origin. Always on, no configuration, and it does
not touch the addon's own connection — Godot was never sending the header that
now gets it rejected.
This does not need active exploitation in the wild to be worth a same-day patch.
It needed one page with a script tag.
A shared secret, if you want a second lock
Origin rejection closes the browser vector completely, but not every local
process: something else running as you on the same machine can still open a
plain WebSocket and claim to be Godot. GODOT_MCP_SECRET closes that too — set
it on the server, set the same value in the editor (same env var, or the
godot_mcp/network/secret project setting), and the handshake is checked in
constant time. Unset on either side, and nothing changes: this is additive, not
a new requirement.
SECURITY.md lists what actually guards the bridge now, in order, instead of
just saying "runs on localhost."
Along the way: coverage found three real bugs
Extending the GDScript suite to 29 more mutating tools (52 of 99 covered → 81)
was meant to be mechanical. It wasn't:
remove_state_machine_transitionnever worked. It calledfind_transition(),
which does not exist onAnimationNodeStateMachine. The call aborted the
handler mid-edit and returned an empty dictionary — nook, noerror, no
message, undo action left open. Fixed by locating the transition index
directly instead of a method that was never there.- Painting a tilemap cell with no TileSet assigned reported plain success.
The cell is stored; nothing can render it, because the source ID resolves
against a TileSet that doesn't exist yet. Refusing would break the legitimate
case of assigning the TileSet afterwards, so bothtilemap_set_celland
tilemap_fill_rectnow succeed and say so in awarningfield. - Tilemap coordinates silently dropped
[x, y]arrays and painted at(0, 0).
Every other coordinate-taking tool here —add_node's position,
setup_collision's size — accepts an array, so trying one here was a
reasonable guess that used to fail quietly. Arrays are now accepted alongside
{x, y}.
None of these three would have been caught by hand. That's the whole argument
for writing the coverage in the first place.
A live activity feed instead of a poll
get_editor_activity only tells you something if you ask, and the digest
riding along on tool responses only arrives when a tool happens to be called —
between calls is exactly when the developer is doing something worth knowing
about. godot-mcp://editor/activity is now a subscribable MCP resource:
subscribe once and the server pushes notifications/resources/updated when the
developer touches something (the agent's own edits are filtered out, and a
burst — dragging a node — coalesces into one notification instead of a dozen).
Nothing is polled while nobody is subscribed.
Also
- CI now runs the GDScript and live-editor suites against two Godot
versions — the advertised minimum (4.5) and the latest stable (4.7) — instead
of one. Both engine breaks this project has had were found by hand, late; a
version matrix turns the next one into a red build instead. - The MCP registry entry now publishes itself on every GitHub release, via
GitHub OIDC (no secret to leak). It had been sitting at 1.0.0 through two
releases because nobody re-ran the manual step.
Upgrade notes
Same tool surface as 1.1.1 — nothing removed, no schemas changed. The security
fix lives in the npm package (the bridge), not the addon, so update the npm
package (npm install -g godot-mcp-bridge@latest, or just let npx pick up
the new version next run) — a reinstalled addon alone does not carry this fix.
If 1.1.1 or earlier is what's actually running today, updating is the same
priority as any other same-day security patch: do it before the next session
where the editor is open in the background while you're also browsing.