mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-18 10:31:30 +08:00
fix(security): CSS injection guard, timeout clamping, session validation, tests (#806)
Community PR #806 by @mr-k-man (security audit round 2, new parts only). - CSS value validation (DANGEROUS_CSS) in cdp-inspector, write-commands, extension inspector - Queue file permissions (0o700/0o600) in cli, server, sidebar-agent - escapeRegExp for frame --url ReDoS fix - Responsive screenshot path validation with validateOutputPath - State load cookie filtering (reject localhost/.internal/metadata cookies) - Session ID format validation in loadSession - /health endpoint: remove currentUrl and currentMessage fields - QueueEntry interface + isValidQueueEntry validator for sidebar-agent - SIGTERM->SIGKILL escalation in timeout handler - Viewport dimension clamping (1-16384), wait timeout clamping (1s-300s) - Cookie domain validation in cookie-import and cookie-import-browser - DocumentFragment-based tab switching (XSS fix in sidepanel) - pollInProgress reentrancy guard for pollChat - toggleClass/injectCSS input validation in extension inspector - Snapshot annotated path validation with realpathSync - 714-line security-audit-r2.test.ts + 33-line learnings-injection.test.ts 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:
@@ -355,6 +355,10 @@
|
||||
function applyStyle(selector, property, value) {
|
||||
// Validate property name: alphanumeric + hyphens only
|
||||
if (!/^[a-zA-Z-]+$/.test(property)) return { error: 'Invalid property name' };
|
||||
// Validate CSS value: block exfiltration vectors (url(), expression(), @import, javascript:, data:)
|
||||
if (/url\s*\(|expression\s*\(|@import|javascript:|data:/i.test(value)) {
|
||||
return { error: 'CSS value contains blocked pattern' };
|
||||
}
|
||||
|
||||
const el = findElement(selector);
|
||||
if (!el) return { error: 'Element not found' };
|
||||
@@ -373,6 +377,9 @@
|
||||
}
|
||||
|
||||
function toggleClass(selector, className, action) {
|
||||
if (!/^[a-zA-Z0-9_-]+$/.test(className)) {
|
||||
return { error: 'Invalid class name' };
|
||||
}
|
||||
const el = findElement(selector);
|
||||
if (!el) return { error: 'Element not found' };
|
||||
|
||||
@@ -387,6 +394,12 @@
|
||||
}
|
||||
|
||||
function injectCSS(id, css) {
|
||||
if (!/^[a-zA-Z0-9_-]+$/.test(id)) {
|
||||
return { error: 'Invalid CSS injection id' };
|
||||
}
|
||||
if (/url\s*\(|expression\s*\(|@import|javascript:|data:/i.test(css)) {
|
||||
return { error: 'CSS contains blocked pattern (url, expression, @import)' };
|
||||
}
|
||||
const styleId = `gstack-inject-${id}`;
|
||||
let styleEl = document.getElementById(styleId);
|
||||
if (!styleEl) {
|
||||
|
||||
Reference in New Issue
Block a user