Skip to content

fix(security): bind internal API and editor servers to loopback - #366

Open
khawarahemad wants to merge 1 commit into
aiko-chan-ai:electron-v3from
khawarahemad:fix/bind-servers-loopback
Open

khawarahemad wants to merge 1 commit into
aiko-chan-ai:electron-v3from
khawarahemad:fix/bind-servers-loopback

Conversation

@khawarahemad

Copy link
Copy Markdown
Contributor

Summary

This PR restricts the internal Express API server and Message Editor static server to listen exclusively on the local loopback interface (127.0.0.1).

Impact

server.listen(0) does not constrain the listener to loopback; in the affected runtime, the server was reachable through the LAN-facing interface. Other devices on the same local network could query internal endpoints (such as /api/v9/users/@me/settings-proto/*) and access or modify local settings.

Root Cause

In src/AppCore/APIServer.ts and src/AppCore/MessageEditorServer.ts, server.listen(0) / app.listen(0) omitted an explicit host parameter, allowing incoming connections from non-loopback network interfaces.

Fix

Explicitly pass "127.0.0.1" to server.listen(0, "127.0.0.1") in APIServer.ts and app.listen(0, "127.0.0.1") in MessageEditorServer.ts.

Validation

  • Validated with npm run test:typescript and npm run build:ts.
  • Verified at runtime on a live instance:
    • curl -k https://127.0.0.1:<port>/ping -> HTTP 200 OK
    • curl -k --connect-timeout 2 https://<LAN_IP>:<port>/ping -> Connection timed out / refused
  • Verified that bot login, Discord gateway connection, and channel message synchronization function normally.

@aiko-chan-ai
aiko-chan-ai requested a lite review from Copilot August 25, 2026 20:10
@aiko-chan-ai aiko-chan-ai added the AI This PR looks AI-assisted. That's fine, this is just a marker. label Aug 25, 2026

Copilot AI 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.

🟡 Changes recommended

The new IPv4-only loopback binding can break existing localhost call sites (IPv6 ::1 resolution) and should be reconciled for compatibility.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR hardens the app’s internal HTTP(S) surfaces by binding the internal Express API server and the Message Editor static server to the IPv4 loopback interface, preventing LAN-accessible exposure of local-only endpoints.

Changes:

  • Bind the HTTPS internal API server listener to 127.0.0.1 explicitly.
  • Bind the Message Editor Express static server listener to 127.0.0.1 explicitly.
File summaries
File Description
src/AppCore/APIServer.ts Explicitly binds the internal HTTPS API server to 127.0.0.1 instead of all interfaces.
src/AppCore/MessageEditorServer.ts Explicitly binds the Message Editor static server to 127.0.0.1 instead of all interfaces.
Review details

Suppressed comments (2)

src/AppCore/MessageEditorServer.ts:32

  • The editor server binds to 127.0.0.1, but the log message still says "API Server" and points to "localhost". This is misleading for debugging and can confuse which server is actually running where.
            logger.log(`API Server listening on http://localhost:${port}`);

src/AppCore/APIServer.ts:96

  • Binding the API server to 127.0.0.1 is good for LAN isolation, but there are still call sites using https://localhost:${this.port} (e.g., src/AppCore/index.ts:414, 437). If those URLs resolve to ::1 first, requests may fail or be delayed because this listener is IPv4-only. Consider updating those URLs to 127.0.0.1 or adding an IPv6 loopback listener (::1) for compatibility.
        server.listen(0, "127.0.0.1").once("listening", callback);
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

export default async function startEditor (): Promise<number> {
return new Promise((resolve, reject) => {
const server = app.listen(0, () => {
const server = app.listen(0, "127.0.0.1", () => {
Comment thread src/AppCore/APIServer.ts
@@ -93,7 +93,7 @@ export default async function startAppServer (): Promise<number> {
resolve(address.port);
logger.log(`API Server listening on https://localhost:${address.port}`);
@aiko-chan-ai

Copy link
Copy Markdown
Owner

I don't have a Linux box/VM to test Copilot's theory, but it's very likely going to throw some weird exceptions

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI This PR looks AI-assisted. That's fine, this is just a marker.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants