Skip to content

httpserver: restrict /websocket/raw to localhost - #3760

Open
Greninja44 wants to merge 3 commits into
ArduPilot:masterfrom
Greninja44:fix/websocket-raw-loopback-check
Open

httpserver: restrict /websocket/raw to localhost#3760
Greninja44 wants to merge 3 commits into
ArduPilot:masterfrom
Greninja44:fix/websocket-raw-loopback-check

Conversation

@Greninja44

@Greninja44 Greninja44 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #3757
The /websocket/raw WebSocket endpoint on TCP/56781 accepts unauthenticated connections from any network interface. Remote hosts can inject arbitrary MAVLink commands into the active vehicle link — for example, changing the flight mode of a disarmed drone.

This adds an IPAddress.IsLoopback() check on the TCP remote endpoint before completing the WebSocket handshake, consistent with the existing protections on /guided? and POST /guide (added in ec2b6fc and 980d2b8).

Applied to both the desktop server (Utilities/httpserver.cs) and the Xamarin copy (ExtLibs/Xamarin/Xamarin/Linked/httpserver.cs).

All built-in clients (WASM, HUD, Blazor) connect to localhost and are unaffected.

Greninja44 and others added 3 commits August 18, 2026 15:35
Fix two bugs in DroneCAN.GetParameters() that caused parameter
enumeration to stop before retrieving all parameters:

1. SemaphoreSlim(1) allowed the while loop to send duplicate
   GetSet requests before receiving responses. When both duplicate
   responses arrived, the index was incremented twice, skipping
   intermediate parameter indices. Changed to SemaphoreSlim(0)
   so the loop blocks until each response arrives.

2. Message filter used a single AND condition that failed to
   filter out service messages from wrong nodes. A stray
   GetSet_res with name_len==0 from another node could trigger
   premature end-of-enumeration. Fixed to use two separate
   conditions matching the proven pattern in SetParameter().
The /websocket/raw WebSocket endpoint accepts unauthenticated
connections from any network interface, allowing remote hosts to
inject arbitrary MAVLink commands into the active vehicle link.

Add an IPAddress.IsLoopback() check on the TCP remote endpoint
before completing the WebSocket handshake, consistent with the
existing protections on /guided? and POST /guide.

Fixes ArduPilot#3757

@fallenmi fallenmi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified that the new guard runs before the WebSocket 101 response and before the raw bridge is installed in both the desktop and Xamarin copies. A socket-level oracle using the same TcpClient.Client.RemoteEndPoint / IPAddress.IsLoopback path sees 127.0.0.1 as loopback and a connection through the host's non-loopback interface as non-loopback, so the latter takes the fail-closed 403 path while the built-in local clients remain allowed. A missing or non-IP endpoint is also rejected.

The net PR diff is limited to these two matching guards. Release, Debug, macOS, and iOS builds are green. The two Android failures are baseline infrastructure failures: exact current base 67a3c4f and this head both fail because the VS18 runner lacks Xamarin.Android.CSharp.targets, with the same MSB4226 error.

This closes the unauthenticated remote-command path without changing the local WebSocket protocol. Looks good to me.

Disclosure: I used OpenAI Codex to inspect the exact head/base, verify the socket address classification, and compare the CI failures; I verified the result.

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.

Is the MAVLink WebSocket on TCP/56781 intended to be remotely writable?

2 participants