add security hardening features (#543)

* add security hardening features

- Add authentication vault (`auth save/login/list/show/delete`) so credentials are stored locally and never exposed to the LLM (fixes Snyk W007)
- Add `--content-boundaries` flag to wrap page-sourced output in structural markers, helping LLMs distinguish tool output from untrusted page content (fixes Snyk W011)
- Add `--allowed-domains` flag to restrict browser navigation to trusted domains
- Add `--action-policy` for static allow/deny gating of action categories, with opt-in `--confirm-actions`/`--confirm-interactive` for orchestrator or human-in-the-loop confirmation
- Add `--max-output` flag to truncate large page outputs, preventing context flooding
- New docs page at /security, updated README, SKILL.md, CLI help text, and templates

* fixes

* fixes

* fixes

* fixes

* fixes

* fixes

* fixes

* docs
This commit is contained in:
Chris Tate
2026-02-25 15:33:20 -06:00
committed by GitHub
parent c0e2b80f8c
commit bc1e917e87
28 changed files with 3444 additions and 476 deletions
+53
View File
@@ -0,0 +1,53 @@
import { randomBytes } from 'node:crypto';
interface PendingConfirmation {
id: string;
action: string;
category: string;
description: string;
command: Record<string, unknown>;
timer: ReturnType<typeof setTimeout>;
}
const AUTO_DENY_TIMEOUT_MS = 60_000;
const pending = new Map<string, PendingConfirmation>();
function generateId(): string {
return `c_${randomBytes(8).toString('hex')}`;
}
export function requestConfirmation(
action: string,
category: string,
description: string,
command: Record<string, unknown>
): { confirmationId: string } {
const id = generateId();
const timer = setTimeout(() => {
pending.delete(id);
}, AUTO_DENY_TIMEOUT_MS);
pending.set(id, {
id,
action,
category,
description,
command,
timer,
});
return { confirmationId: id };
}
export function getAndRemovePending(
id: string
): { command: Record<string, unknown>; action: string } | null {
const entry = pending.get(id);
if (!entry) return null;
clearTimeout(entry.timer);
pending.delete(id);
return { command: entry.command, action: entry.action };
}