From 6f5d9f457e577ef8cbeb3577bf2d2863580c4907 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:31:26 +0000 Subject: [PATCH 1/4] fix: prevent token leakage via open redirects in jFetch This commit modifies the custom fetch wrapper `jFetch` to set `redirect: 'error'` when sending requests with an authorization token. This prevents accidental token leakage via cross-origin open redirects, a critical security defense-in-depth measure. Also adds corresponding unit tests in `security.test.js` to ensure the redirect option is tracked. Co-authored-by: n24q02m <135627235+n24q02m@users.noreply.github.com> --- .Jules/sentinel.md | 4 ++++ background.js | 1 + tests/security.test.js | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.Jules/sentinel.md b/.Jules/sentinel.md index 981886a..21bd7de 100644 --- a/.Jules/sentinel.md +++ b/.Jules/sentinel.md @@ -2,3 +2,7 @@ **Vulnerability:** The extension's Content Security Policy (CSP) in `manifest.json` lacked explicit `default-src 'none'` and broad network constraints, relying solely on script and object restrictions. **Learning:** A permissive CSP allows unexpected resource loading and potential data exfiltration if an XSS vulnerability occurs. A strict whitelist (`default-src 'none'`) provides a robust defense-in-depth layer. **Prevention:** Always define a strict CSP for extensions, setting `default-src 'none'` and explicitly allowing only required origins (e.g., `connect-src`). +## 2026-08-27 - Prevent token leakage via open redirects +**Vulnerability:** The `jFetch` wrapper did not constrain HTTP redirects when sending requests with sensitive credentials (API tokens), making it susceptible to accidental token leakage via cross-origin open redirects. +**Learning:** When implementing network wrappers (e.g., `fetch`) that transmit sensitive credentials like API tokens, conditionally setting `redirect: 'error'` or `redirect: 'manual'` in the fetch options when credentials are provided prevents accidental token leakage via cross-origin open redirects without breaking legitimate API endpoints that rely on standard HTTP redirects. +**Prevention:** Always restrict redirect behavior when sending authorization headers in custom fetch wrappers. diff --git a/background.js b/background.js index 61728be..6495fb0 100644 --- a/background.js +++ b/background.js @@ -63,6 +63,7 @@ async function jFetch(url, options = {}) { if (typeof token !== 'string') throw new Error('Token must be a string') if (/[\r\n]/.test(token)) throw new Error('Invalid token: contains newline') headers.Authorization = `token ${token}` + rest.redirect = rest.redirect || 'error' } const controller = new AbortController() diff --git a/tests/security.test.js b/tests/security.test.js index 6be189e..c566bf1 100644 --- a/tests/security.test.js +++ b/tests/security.test.js @@ -162,7 +162,10 @@ function setupEnvironment(initialTabs = {}) { const sandbox = { chrome: chromeMock, - fetch: async () => ({ ok: true, json: async () => [], text: async () => ")]}'\n\n4\n[[]]" }), + fetch: async (url, options) => { + chromeMock.lastFetch = { url, options } + return { ok: true, json: async () => [], text: async () => ")]}'\n\n4\n[[]]" } + }, setTimeout, Date, Promise, @@ -312,6 +315,18 @@ describe('jFetch SSRF Security', () => { message: /Security Error: Refusing to send GitHub token to non-GitHub origin/ }) }) + + it('should set redirect to error when token is provided and redirect is undefined', async () => { + const { sandbox } = setupEnvironment() + await sandbox.jFetch('https://api.github.com/test', { token: 'secret-token' }) + assert.strictEqual(sandbox.chrome.lastFetch.options.redirect, 'error') + }) + + it('should preserve existing redirect option when token is provided', async () => { + const { sandbox } = setupEnvironment() + await sandbox.jFetch('https://api.github.com/test', { token: 'secret-token', redirect: 'manual' }) + assert.strictEqual(sandbox.chrome.lastFetch.options.redirect, 'manual') + }) }) describe('getTabConfig Path Traversal Security', () => { From ecc2b70046deebb1fa240ef1c6578fec7f8c2e87 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:43:54 +0000 Subject: [PATCH 2/4] fix: prevent token leakage via open redirects in jFetch This commit modifies the custom fetch wrapper `jFetch` to set `redirect: 'error'` when sending requests with an authorization token. This prevents accidental token leakage via cross-origin open redirects, a critical security defense-in-depth measure. Also adds corresponding unit tests in `security.test.js` and `background.test.js` to ensure the redirect option is tracked and to satisfy code coverage requirements. Co-authored-by: n24q02m <135627235+n24q02m@users.noreply.github.com> --- tests/background.test.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/background.test.js b/tests/background.test.js index ad10dfa..f661796 100644 --- a/tests/background.test.js +++ b/tests/background.test.js @@ -1597,6 +1597,28 @@ describe('jFetch', () => { assert.strictEqual(capturedHeaders.Authorization, 'token valid-token') }) + it('should set redirect to error when token is provided and redirect is undefined', async () => { + const { sandbox } = setupEnvironment() + let capturedOptions = null + sandbox.fetch = async (_url, options) => { + capturedOptions = options + return { ok: true } + } + await sandbox.test_jFetch('https://api.github.com/test', { token: 'secret-token' }) + assert.strictEqual(capturedOptions.redirect, 'error') + }) + + it('should preserve existing redirect option when token is provided', async () => { + const { sandbox } = setupEnvironment() + let capturedOptions = null + sandbox.fetch = async (_url, options) => { + capturedOptions = options + return { ok: true } + } + await sandbox.test_jFetch('https://api.github.com/test', { token: 'secret-token', redirect: 'manual' }) + assert.strictEqual(capturedOptions.redirect, 'manual') + }) + it('should throw an error for HTTP 500 status code', async () => { const { sandbox } = setupEnvironment() sandbox.fetch = async () => ({ From 12101bb93aa113804adba21605dfe87cf98a877c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:51:44 +0000 Subject: [PATCH 3/4] test: duplicate redirect tests in background.test.js for coverage tracking This commit duplicates the redirect tests from `security.test.js` to `background.test.js` to ensure the coverage tracker accurately measures the added redirect configurations in `jFetch` which addresses the Codecov failure. Co-authored-by: n24q02m <135627235+n24q02m@users.noreply.github.com> From 4709da5f46c627cdf445714bf6ca113e377d3993 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:59:02 +0000 Subject: [PATCH 4/4] fix: prevent token leakage via open redirects in jFetch This commit modifies the custom fetch wrapper `jFetch` to set `redirect: 'error'` when sending requests with an authorization token. This prevents accidental token leakage via cross-origin open redirects, a critical security defense-in-depth measure. Also adds corresponding unit tests in `security.test.js` and `background.test.js` to ensure the redirect option is tracked and to satisfy code coverage requirements. Co-authored-by: n24q02m <135627235+n24q02m@users.noreply.github.com>