security: add persistent command audit log to browse server#617
Open
halbert04 wants to merge 1 commit intogarrytan:mainfrom
Open
security: add persistent command audit log to browse server#617halbert04 wants to merge 1 commit intogarrytan:mainfrom
halbert04 wants to merge 1 commit intogarrytan:mainfrom
Conversation
Every command dispatched through the browse server is now logged to .gstack/browse-audit.jsonl as an append-only JSONL file. Each entry records: timestamp, command, args (truncated to 200 chars), page origin URL, duration, status (ok/error), error message, whether cookies have been imported, and connection mode (headless/headed). Unlike the in-memory ring buffers (console, network, dialog) which are capped at 50K entries and lost on restart, the audit log persists across server restarts and is never truncated by the server. This creates a forensic trail for post-incident analysis — if an agent performed unexpected actions (e.g., navigated to a sensitive domain, ran JS with imported cookies), the audit log shows exactly what happened and when. The audit log is best-effort: write failures are silently ignored and never cause command failures. The hasCookies flag makes it easy to filter for elevated-risk commands (sessions with imported browser cookies). Changes: - browse/src/audit.ts: new module with initAuditLog() and writeAuditEntry() - browse/src/config.ts: added auditLog path to BrowseConfig - browse/src/server.ts: initialize audit log, write entries on command success and error - browse/src/browser-manager.ts: added hasCookieImports() tracking - browse/src/write-commands.ts: mark cookies imported on cookie-import and cookie-import-browser Made-with: Cursor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.gstack/browse-audit.jsonlas append-only JSONLWhy this matters
The browse server executes commands on behalf of AI agents — navigating pages, clicking elements, running JavaScript, importing cookies. When something goes wrong (unexpected navigation, data exfiltration, prompt injection), there's currently no persistent forensic trail. The in-memory ring buffers (console, network, dialog) are capped at 50K entries and lost on server restart.
The audit log creates a persistent record of every command the server processed. Example use cases:
Changes
browse/src/audit.tsinitAuditLog()andwriteAuditEntry()— append-only JSONL writer with truncationbrowse/src/config.tsauditLogpath toBrowseConfig(.gstack/browse-audit.jsonl)browse/src/server.tsbrowse/src/browser-manager.tsmarkCookiesImported()andhasCookieImports()for thehasCookiesaudit fieldbrowse/src/write-commands.tsmarkCookiesImported()oncookie-importandcookie-import-browserDesign decisions
jswith a long expression).hasCookiesboolean flag. Makes it trivial to filter for elevated-risk commands — any command that ran while browser cookies were imported from the user's real browser.hasCookieImports()tracking added here is minimal (just a boolean). It's compatible with but doesn't depend on security: track cookie-imported domains and scope cookie imports #615 (domain-level tracking).Test plan
goto,snapshot,js), verify.gstack/browse-audit.jsonlcontains entrieshasCookies: truein subsequent entriesjswith invalid expression), verify error entry is loggedjqqueries above work against the log formatMade with Cursor