mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 03:35:09 +02:00
fix: security audit round 2 (v0.13.4.0) (#640)
* fix: chrome-cdp localhost-only binding Restrict Chrome CDP to localhost by adding --remote-debugging-address=127.0.0.1 and --remote-allow-origins to prevent network-accessible debugging sessions. Clears 1 Socket anomaly (Chrome CDP session exposure). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: extension sender validation + message type allowlist Add sender.id check and ALLOWED_TYPES allowlist to the Chrome extension's message handler. Defense-in-depth against message spoofing from external extensions or future externally_connectable changes. Clears 2 Socket anomalies (extension permissions). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: checksum-verified bun install Replace unverified curl|bash bun installation with checksum-verified download-then-execute pattern. The install script is downloaded, sha256 verified against a known hash, then executed. Preserves the Bun-native install path without adding a Node/npm dependency. Clears Snyk W012 + 3 Socket anomalies. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: content trust boundary markers in browse output Wrap page-content commands (text, html, links, forms, accessibility, console, dialog, snapshot) with --- BEGIN/END UNTRUSTED EXTERNAL CONTENT --- markers. Covers direct commands (server.ts), chain sub-commands, and snapshot output (meta-commands.ts). Adds PAGE_CONTENT_COMMANDS set and wrapUntrustedContent() helper in commands.ts (single source of truth, DRY). Expands the SKILL.md trust warning with explicit processing rules for agents. Clears Snyk W011 (third-party content exposure). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: harden trust boundary markers against escape attacks - Sanitize URLs in markers (remove newlines, cap at 200 chars) to prevent marker injection via history.pushState - Escape marker strings in content (zero-width space) so malicious pages can't forge the END marker to break out of the untrusted block - Wrap resume command snapshot with trust boundary markers - Wrap diff command output with trust boundary markers - Wrap watch stop last snapshot with trust boundary markers Found by cross-model adversarial review (Claude + Codex). * chore: bump version and changelog (v0.13.4.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: gitignore .factory/ and remove from tracking Factory Droid support was removed in this branch. The .factory/ directory was re-added by merging main (which had v0.13.5.0 Factory support). Gitignore it so it stays out. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,15 +45,17 @@ describe('Audit compliance', () => {
|
||||
expect(completionSection).toContain('_TEL" != "off"');
|
||||
});
|
||||
|
||||
// Fix 3: W012 — Bun install is version-pinned
|
||||
test('bun install commands use version pinning', () => {
|
||||
// Round 2 Fix 1: W012 — Bun install uses checksum verification
|
||||
test('bun install uses checksum-verified method', () => {
|
||||
const browseResolver = readFileSync(join(ROOT, 'scripts/resolvers/browse.ts'), 'utf-8');
|
||||
expect(browseResolver).toContain('BUN_VERSION');
|
||||
// Should not have unpinned curl|bash (without BUN_VERSION on same line)
|
||||
const lines = browseResolver.split('\n');
|
||||
expect(browseResolver).toContain('shasum -a 256');
|
||||
expect(browseResolver).toContain('BUN_INSTALL_SHA');
|
||||
const setup = readFileSync(join(ROOT, 'setup'), 'utf-8');
|
||||
// Setup error message should not have unverified curl|bash
|
||||
const lines = setup.split('\n');
|
||||
for (const line of lines) {
|
||||
if (line.includes('bun.sh/install') && line.includes('bash') && !line.includes('BUN_VERSION') && !line.includes('command -v')) {
|
||||
throw new Error(`Unpinned bun install found: ${line.trim()}`);
|
||||
if (line.includes('bun.sh/install') && line.includes('| bash') && !line.includes('shasum')) {
|
||||
throw new Error(`Unverified bun install found: ${line.trim()}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -69,6 +71,17 @@ describe('Audit compliance', () => {
|
||||
expect(between.toLowerCase()).toContain('untrusted');
|
||||
});
|
||||
|
||||
// Round 2 Fix 2: Trust boundary markers + helper + wrapping in all paths
|
||||
test('browse wraps untrusted content with trust boundary markers', () => {
|
||||
const commands = readFileSync(join(ROOT, 'browse/src/commands.ts'), 'utf-8');
|
||||
expect(commands).toContain('PAGE_CONTENT_COMMANDS');
|
||||
expect(commands).toContain('wrapUntrustedContent');
|
||||
const server = readFileSync(join(ROOT, 'browse/src/server.ts'), 'utf-8');
|
||||
expect(server).toContain('wrapUntrustedContent');
|
||||
const meta = readFileSync(join(ROOT, 'browse/src/meta-commands.ts'), 'utf-8');
|
||||
expect(meta).toContain('wrapUntrustedContent');
|
||||
});
|
||||
|
||||
// Fix 5: Data flow documentation in review.ts
|
||||
test('review.ts has data flow documentation', () => {
|
||||
const review = readFileSync(join(ROOT, 'scripts/resolvers/review.ts'), 'utf-8');
|
||||
@@ -76,6 +89,20 @@ describe('Audit compliance', () => {
|
||||
expect(review).toContain('Data NOT sent');
|
||||
});
|
||||
|
||||
// Round 2 Fix 3: Extension sender validation + message type allowlist
|
||||
test('extension background.js validates message sender', () => {
|
||||
const bg = readFileSync(join(ROOT, 'extension/background.js'), 'utf-8');
|
||||
expect(bg).toContain('sender.id !== chrome.runtime.id');
|
||||
expect(bg).toContain('ALLOWED_TYPES');
|
||||
});
|
||||
|
||||
// Round 2 Fix 4: Chrome CDP binds to localhost only
|
||||
test('chrome-cdp binds to localhost only', () => {
|
||||
const cdp = readFileSync(join(ROOT, 'bin/chrome-cdp'), 'utf-8');
|
||||
expect(cdp).toContain('--remote-debugging-address=127.0.0.1');
|
||||
expect(cdp).toContain('--remote-allow-origins=');
|
||||
});
|
||||
|
||||
// Fix 2+6: All generated SKILL.md files with telemetry are conditional
|
||||
test('all generated SKILL.md files with telemetry calls use conditional pattern', () => {
|
||||
const skills = getAllSkillMds();
|
||||
|
||||
Reference in New Issue
Block a user