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:
@@ -53,6 +53,9 @@ const launchSchema = baseCommandSchema.extend({
|
||||
downloadPath: z.string().optional(),
|
||||
profile: z.string().optional(),
|
||||
storageState: z.string().optional(),
|
||||
allowedDomains: z.array(z.string()).optional(),
|
||||
actionPolicy: z.string().optional(),
|
||||
confirmActions: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
const navigateSchema = baseCommandSchema.extend({
|
||||
@@ -873,6 +876,53 @@ const windowNewSchema = baseCommandSchema.extend({
|
||||
.optional(),
|
||||
});
|
||||
|
||||
const authProfileName = z
|
||||
.string()
|
||||
.min(1)
|
||||
.regex(/^[a-zA-Z0-9_-]+$/, {
|
||||
message: 'Profile name must contain only alphanumeric characters, hyphens, and underscores',
|
||||
});
|
||||
|
||||
const authSaveSchema = baseCommandSchema.extend({
|
||||
action: z.literal('auth_save'),
|
||||
name: authProfileName,
|
||||
url: z.string().min(1),
|
||||
username: z.string().min(1),
|
||||
password: z.string().min(1),
|
||||
usernameSelector: z.string().optional(),
|
||||
passwordSelector: z.string().optional(),
|
||||
submitSelector: z.string().optional(),
|
||||
});
|
||||
|
||||
const authLoginSchema = baseCommandSchema.extend({
|
||||
action: z.literal('auth_login'),
|
||||
name: authProfileName,
|
||||
});
|
||||
|
||||
const authListSchema = baseCommandSchema.extend({
|
||||
action: z.literal('auth_list'),
|
||||
});
|
||||
|
||||
const authDeleteSchema = baseCommandSchema.extend({
|
||||
action: z.literal('auth_delete'),
|
||||
name: authProfileName,
|
||||
});
|
||||
|
||||
const authShowSchema = baseCommandSchema.extend({
|
||||
action: z.literal('auth_show'),
|
||||
name: authProfileName,
|
||||
});
|
||||
|
||||
const confirmSchema = baseCommandSchema.extend({
|
||||
action: z.literal('confirm'),
|
||||
confirmationId: z.string().min(1),
|
||||
});
|
||||
|
||||
const denySchema = baseCommandSchema.extend({
|
||||
action: z.literal('deny'),
|
||||
confirmationId: z.string().min(1),
|
||||
});
|
||||
|
||||
// Union schema for all commands
|
||||
const commandSchema = z.discriminatedUnion('action', [
|
||||
launchSchema,
|
||||
@@ -1010,6 +1060,13 @@ const commandSchema = z.discriminatedUnion('action', [
|
||||
diffSnapshotSchema,
|
||||
diffScreenshotSchema,
|
||||
diffUrlSchema,
|
||||
confirmSchema,
|
||||
denySchema,
|
||||
authSaveSchema,
|
||||
authLoginSchema,
|
||||
authListSchema,
|
||||
authDeleteSchema,
|
||||
authShowSchema,
|
||||
]);
|
||||
|
||||
// Parse result type
|
||||
|
||||
Reference in New Issue
Block a user