{"record":{"id":"182795634ba8d884","repo":"joewalnes/websocketd","slug":"same-origin-policy-violated","errorCode":null,"errorMessage":"same origin policy violated","messagePattern":"same origin policy violated","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libwebsocketd/http.go","lineNumber":379,"sourceCode":"\t}\n\n\tlog.Associate(\"origin\", originParsed.String())\n\n\tif config.SameOrigin || config.AllowOrigins != nil {\n\t\toriginServer, originPort, err := tellHostPort(originParsed.Host, originParsed.Scheme == \"https\")\n\t\tif err != nil {\n\t\t\tlog.Access(\"session\", \"Origin hostname parsing error: %s\", err)\n\t\t\treturn err\n\t\t}\n\t\tif config.SameOrigin {\n\t\t\tlocalServer, localPort, err := tellHostPort(req.Host, req.TLS != nil)\n\t\t\tif err != nil {\n\t\t\t\tlog.Access(\"session\", \"Request hostname parsing error: %s\", err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif originServer != localServer || originPort != localPort {\n\t\t\t\tlog.Access(\"session\", \"Same origin policy mismatch\")\n\t\t\t\treturn fmt.Errorf(\"same origin policy violated\")\n\t\t\t}\n\t\t}\n\t\tif config.AllowOrigins != nil {\n\t\t\tif !matchOrigin(originServer, originPort, originParsed.Scheme, config.AllowOrigins) {\n\t\t\t\tlog.Access(\"session\", \"Origin is not listed in allowed list\")\n\t\t\t\treturn fmt.Errorf(\"origin list matches were not found\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// matchOrigin checks if the given origin server/port/scheme matches any entry\n// in the allowed origins list. Extracted for testability.\n//\n// Port semantics (issue #473): an entry with an explicit port matches that\n// port only. A portless entry matches only the scheme's default port (80 for\n// http, 443 for https — both, if the entry carries no scheme). Appending","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/joewalnes/websocketd/blob/7a8683dc7f9778dc615945aaed2a8dc77290227b/libwebsocketd/http.go#L361-L397","documentation":"checkOrigin enforces cross-origin WebSocket security. When the request's Origin header parses to a host/port different from the server's own host/port (and no --origin list is consulted first to save it), the upgrade is rejected with this error and gorilla/websocket answers the handshake with HTTP 403. It exists to prevent other websites' JavaScript from driving your websocketd scripts with the user's credentials.","triggerScenarios":"A browser page served from http://app.example.com:8080 opens a WebSocket to ws://otherhost:9999/ while the server runs without --origin; or the page uses localhost vs 127.0.0.1 mismatch; or a reverse proxy rewrites the Host so the server compares it against a different origin than the browser sent.","commonSituations":"Frontend on a different port than the dev server; serving the HTML from a CDN/static host while websocketd runs elsewhere; forgetting the --origin flag when splitting frontend and backend; tests (TestCheckOrigin) exercising mismatched host/port pairs.","solutions":["Add the frontend's exact origin to --origin, e.g. --origin=http://app.example.com:8080 (repeatable or comma-separated per matchOrigin semantics).","Serve the client page from the same host and port as websocketd so the same-origin check passes automatically.","If behind a proxy, ensure the Host header forwarded to websocketd matches the origin your page uses, or disable the proxy's host rewriting.","For non-browser clients (curl, wscat) the Origin header is irrelevant or absent — this only blocks browser handshakes that send a mismatching Origin."],"exampleFix":"// before\nwebsocketd --port=8080 ./chat.sh\n// after\nwebsocketd --port=8080 --origin=http://localhost:3000 ./chat.sh","handlingStrategy":"validation","validationCode":"const url = new URL('ws://localhost:8080/echo');\nif (url.host !== location.host) throw new Error(`origin ${url.host} != server ${location.host}; pass --origin=${location.origin}`);","typeGuard":null,"tryCatchPattern":"try {\n  const ws = new WebSocket('ws://localhost:8080/echo');\n  ws.onerror = () => console.error('handshake rejected (likely 403 origin mismatch)');\n} catch (e) { console.error('ws setup failed', e); }","preventionTips":["Serve the client page from the same host:port as websocketd during development.","Explicitly pass --origin for every origin allowed to connect; don't rely on same-origin defaults in prod.","After changing ports or scheme (http→https), update the origin list and test the handshake.","Check the server's 'Same origin policy mismatch' access log line to learn the exact origin to allow."],"tags":["websocket","security","cors","origin"],"backgroundTag":"websocket-origin-rejected","analyzedSha":"7a8683dc7f9778dc615945aaed2a8dc77290227b","analyzedAt":"2026-09-03T13:52:22.309Z","contentChangedAt":"2026-09-03T13:52:22.309Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}