Skip to content

🔒 Restrict WebSocket Origins to Mitigate CSWSH#15

Open
adcondev wants to merge 2 commits intomasterfrom
fix-cswsh-cors-7606051191821757871
Open

🔒 Restrict WebSocket Origins to Mitigate CSWSH#15
adcondev wants to merge 2 commits intomasterfrom
fix-cswsh-cors-7606051191821757871

Conversation

@adcondev
Copy link
Owner

🧹 🔒 Restrict WebSocket Origins to Mitigate CSWSH

🎯 What

  • Fixed a security vulnerability where the WebSocket server accepted connections from any origin (OriginPatterns: ["*"]).
  • Introduced a configurable AllowedOrigins setting in config.Environment and server.Config.
  • Updated internal/server/server.go to use the configured allowed origins in OriginPatterns and removed InsecureSkipVerify: true.
  • Updated internal/daemon/daemon.go to pass the configuration to the server.
  • Set strict defaults for the remote environment (localhost and file:// only) while keeping local permissive for development (but overridable).
  • Added AllowedOrigins variable injectable via ldflags for deployment flexibility.

💡 Why

  • To prevent Cross-Site WebSocket Hijacking (CSWSH) attacks where a malicious site could connect to the local ticket daemon and print unauthorized jobs or extract information.
  • By restricting allowed origins, we ensure that only authorized applications (e.g., the POS web app) can communicate with the daemon.

✅ Verification

  • Created a new test internal/server/server_test.go that:
    • Verifies connections from allowed origins succeed.
    • Verifies connections from disallowed origins (e.g., evil.com) are rejected.
    • Verifies that empty configuration enforces Same Origin Policy.
  • Ran go test locally with a mock poster dependency and confirmed the test passes with the fix and fails without it.

✨ Result

  • The WebSocket server now enforces origin checks.
  • Production deployments (remote) default to a safer configuration.
  • Users can configure allowed origins via AllowedOrigins ldflag (comma-separated list).

PR created automatically by Jules for task 7606051191821757871 started by @adcondev

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules
Copy link

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 19, 2026 20:29
@github-actions
Copy link

github-actions bot commented Feb 19, 2026

⚡ Benchmark Results

⚠️ No benchmarks found in the current codebase.

To add benchmarks, create functions starting with Benchmark in *_test.go files.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the daemon’s WebSocket endpoint against Cross-Site WebSocket Hijacking (CSWSH) by replacing permissive origin acceptance with configurable origin restrictions that flow from environment config into the server.

Changes:

  • Add AllowedOrigins to configuration (config.Environment) with environment defaults and an ldflags override.
  • Wire AllowedOrigins through daemon startup into server.Config, and apply it via websocket.AcceptOptions.OriginPatterns (removing InsecureSkipVerify: true).
  • Add WebSocket origin enforcement tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
internal/server/server.go Uses configured origin patterns during WebSocket Accept and removes insecure verification bypass.
internal/config/config.go Introduces AllowedOrigins (env + ldflags override) and sets environment defaults.
internal/daemon/daemon.go Passes environment AllowedOrigins into the WebSocket server configuration.
internal/server/server_test.go Adds tests to validate allowed vs. disallowed origins and a same-origin scenario.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// Override allowed origins from ldflags if provided
if AllowedOrigins != "" {
cfg.AllowedOrigins = strings.Split(AllowedOrigins, ",")
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

Parsing AllowedOrigins from the ldflag with strings.Split leaves leading/trailing whitespace intact and can introduce empty entries (e.g., trailing comma). This can make valid origins fail to match unexpectedly and makes configuration fragile. Consider splitting, trimming spaces on each entry, and filtering out empty strings before assigning cfg.AllowedOrigins (optionally validate patterns and log/ignore invalid ones).

Suggested change
cfg.AllowedOrigins = strings.Split(AllowedOrigins, ",")
rawOrigins := strings.Split(AllowedOrigins, ",")
cleanOrigins := make([]string, 0, len(rawOrigins))
for _, origin := range rawOrigins {
trimmed := strings.TrimSpace(origin)
if trimmed == "" {
continue
}
cleanOrigins = append(cleanOrigins, trimmed)
}
if len(cleanOrigins) > 0 {
cfg.AllowedOrigins = cleanOrigins
}

Copilot uses AI. Check for mistakes.
Comment on lines 42 to 68
// Case A: Connection from Allowed Origin
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

opts := &websocket.DialOptions{
HTTPHeader: http.Header{
"Origin": []string{"http://good.com"},
},
}

conn, _, err := websocket.Dial(ctx, u, opts)
if err != nil {
t.Fatalf("Connection from good.com failed: %v", err)
}
conn.Close(websocket.StatusNormalClosure, "")

// Case B: Connection from Disallowed Origin
optsBad := &websocket.DialOptions{
HTTPHeader: http.Header{
"Origin": []string{"http://evil.com"},
},
}

_, _, err = websocket.Dial(ctx, u, optsBad)
if err == nil {
t.Fatalf("Connection from evil.com succeeded (should fail)")
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The negative-origin assertions only check that websocket.Dial returns an error; a timeout/cancellation or other handshake failure would also satisfy this, which can mask regressions. To make the security behavior explicit and reduce flakiness, use a fresh context per dial and assert the failure is specifically an origin rejection (e.g., inspect the HTTP response status / close status / error type returned by the dial).

Copilot uses AI. Check for mistakes.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@codecov-commenter
Copy link

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 26.66667% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/config/config.go 0.00% 7 Missing ⚠️
internal/daemon/daemon.go 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

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