mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-06 13:45:35 +02:00
fix(security): IPv6 ULA blocking, cookie redaction, per-tab cancel, targeted token (#664)
Community PR #664 by @mr-k-man (security audit round 1, new parts only). - IPv6 ULA prefix blocking (fc00::/7) in url-validation.ts with false-positive guard for hostnames like fd.example.com - Cookie value redaction for tokens, API keys, JWTs in browse cookies command - Per-tab cancel files in killAgent() replacing broken global kill-signal - design/serve.ts: realpathSync upgrade prevents symlink bypass in /api/reload - extension: targeted getToken handler replaces token-in-health-broadcast - Supabase migration 003: column-level GRANT restricts anon UPDATE scope - Telemetry sync: upsert error logging - 10 new tests for IPv6, cookie redaction, DNS rebinding, path traversal Co-Authored-By: mr-k-man <mr-k-man@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+15
-4
@@ -87,8 +87,8 @@ function setConnected(healthData) {
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#F59E0B' });
|
||||
chrome.action.setBadgeText({ text: ' ' });
|
||||
|
||||
// Broadcast health to popup and side panel (include token for sidepanel auth)
|
||||
chrome.runtime.sendMessage({ type: 'health', data: { ...healthData, token: authToken } }).catch((err) => {
|
||||
// Broadcast health to popup and side panel (token excluded — use getToken message instead)
|
||||
chrome.runtime.sendMessage({ type: 'health', data: healthData }).catch((err) => {
|
||||
console.debug('[gstack bg] No listener for health broadcast:', err.message);
|
||||
});
|
||||
|
||||
@@ -285,7 +285,7 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
}
|
||||
|
||||
const ALLOWED_TYPES = new Set([
|
||||
'getPort', 'setPort', 'getServerUrl', 'fetchRefs',
|
||||
'getPort', 'setPort', 'getServerUrl', 'getToken', 'fetchRefs',
|
||||
'openSidePanel', 'sidebarOpened', 'command', 'sidebar-command',
|
||||
// Inspector message types
|
||||
'startInspector', 'stopInspector', 'elementPicked', 'pickerCancelled',
|
||||
@@ -315,7 +315,18 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
return true;
|
||||
}
|
||||
|
||||
// getToken handler removed — token distributed via health broadcast
|
||||
// Token delivered via targeted sendResponse, not broadcast — limits exposure.
|
||||
// Only respond to extension pages (sidepanel/popup) — content scripts have
|
||||
// sender.tab set, so reject those to prevent token access from injected contexts.
|
||||
if (msg.type === 'getToken') {
|
||||
if (sender.tab) {
|
||||
console.warn('[gstack] Rejected getToken from content script context');
|
||||
sendResponse({ token: null });
|
||||
} else {
|
||||
sendResponse({ token: authToken });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.type === 'fetchRefs') {
|
||||
fetchAndRelayRefs().then(() => sendResponse({ ok: true }));
|
||||
|
||||
@@ -1570,7 +1570,10 @@ chrome.runtime.onMessage.addListener((msg) => {
|
||||
if (msg.type === 'health') {
|
||||
if (msg.data) {
|
||||
const url = `http://127.0.0.1:${msg.data.port || 34567}`;
|
||||
updateConnection(url, msg.data.token);
|
||||
// Request token via targeted sendResponse (not broadcast) to limit exposure
|
||||
chrome.runtime.sendMessage({ type: 'getToken' }, (resp) => {
|
||||
updateConnection(url, resp?.token || null);
|
||||
});
|
||||
applyChatEnabled(!!msg.data.chatEnabled);
|
||||
} else {
|
||||
updateConnection(null);
|
||||
|
||||
Reference in New Issue
Block a user