Skip to main content

Action Policies

Action policies provide fine-grained control over what actions an AI agent can perform. Use static policy files to gate destructive actions or require explicit confirmation for sensitive operations.

Quick Start

# Create policy file
cat > policy.json <<EOF
{
  "default": "deny",
  "allow": ["navigate", "click", "fill", "get", "snapshot"]
}
EOF

# Apply policy
agent-browser --action-policy ./policy.json open example.com

Policy File Format

Action policies are JSON files with the following structure:
{
  "default": "allow" | "deny",
  "allow": ["category1", "category2"],
  "deny": ["category3", "category4"]
}

Fields

FieldTypeRequiredDescription
default”allow” | “deny”YesDefault policy for actions not in allow/deny lists
allowstring[]NoAction categories to explicitly allow
denystring[]NoAction categories to explicitly deny (takes precedence)

Action Categories

Actions are grouped into categories for easier policy management:
CategoryActionsDescription
navigatenavigate, back, forward, reload, tab_newPage navigation
clickclick, dblclick, tapClick interactions
fillfill, type, keyboard, inserttext, select, multiselect, check, uncheck, clear, selectall, setvalueForm input and text entry
downloaddownload, waitfordownloadFile downloads
uploaduploadFile uploads
evalevaluate, evalhandle, addscript, addinitscript, addstyle, expose, setcontentJavaScript evaluation (high risk)
snapshotsnapshot, screenshot, pdf, diff_snapshot, diff_screenshot, diff_urlPage inspection and diffing
scrollscroll, scrollintoviewScrolling
waitwait, waitforurl, waitforloadstate, waitforfunctionWaiting operations
getgettext, content, innerhtml, innertext, inputvalue, url, title, getattribute, count, boundingbox, styles, isvisible, isenabled, ischecked, responsebody, getbyrole, getbytext, etc.Read-only data retrieval
networkroute, unroute, requestsNetwork interception
statestate_save, state_load, cookies_set, storage_set, credentialsBrowser state manipulation
interacthover, focus, drag, press, keydown, keyup, mousemove, mousedown, mouseup, wheel, dispatchLow-level interactions

Policy Evaluation

When an action is requested, the policy is evaluated in this order:
  1. Internal actions - Always allowed (launch, close, session management, etc.)
  2. Explicit deny - If category is in deny list, action is denied
  3. Confirmation required - If category is in --confirm-actions, prompt user (if interactive)
  4. Explicit allow - If category is in allow list, action is allowed
  5. Default policy - Use default value (“allow” or “deny”)

Internal Actions

These actions bypass policy checks and are always allowed:
  • Browser management: launch, close, tab_list, tab_switch, tab_close
  • Session management: session
  • Information: cookies_get, storage_get, state_list, state_show
  • Debugging: console, errors, highlight, trace_start, trace_stop
  • Auth: auth_save, auth_login, auth_list, auth_delete, auth_show
  • Confirmation: confirm, deny

Common Policy Patterns

Read-Only Agent

Allow only inspection, no interaction:
{
  "default": "deny",
  "allow": ["navigate", "get", "snapshot", "scroll", "wait"]
}

Safe Interaction Agent

Allow navigation and form filling, deny dangerous actions:
{
  "default": "allow",
  "deny": ["eval", "download", "upload", "network", "state"]
}

Minimal Permissions

Only essential actions:
{
  "default": "deny",
  "allow": ["navigate", "click", "fill", "get", "snapshot"]
}

Development Mode

Allow everything except eval:
{
  "default": "allow",
  "deny": ["eval"]
}

Action Confirmation

Require explicit user approval for sensitive action categories:
# Require confirmation for eval and download
agent-browser \
  --confirm-actions eval,download \
  --confirm-interactive \
  open example.com

Confirmation Flow

When an action requires confirmation:
  1. Agent requests the action
  2. CLI prompts user with action details
  3. User approves (confirm) or denies (deny)
  4. Action proceeds or is rejected
Example:
# Agent tries to evaluate JavaScript
agent-browser eval "console.log('test')"

# User sees prompt:
# Action requires confirmation:
#   Category: eval
#   Action: Evaluate JavaScript: console.log('test')
# 
# Approve this action?
#   agent-browser confirm
#   agent-browser deny

# User approves
agent-browser confirm

# Action executes

Interactive vs Non-Interactive

  • Interactive mode (--confirm-interactive): Prompts user via CLI
  • Non-interactive mode: Auto-denies if stdin is not a TTY
This prevents hanging in CI/CD environments.

Confirmation Categories

Common categories to require confirmation:
  • eval - JavaScript execution (high risk)
  • download - File downloads (data exfiltration risk)
  • upload - File uploads (may leak local files)
  • network - Network interception (can modify responses)
  • state - State manipulation (can steal cookies)

Hot Reloading

Policy files are automatically reloaded every 5 seconds. Update the policy without restarting the browser:
# Start with initial policy
agent-browser --action-policy ./policy.json open example.com

# Edit policy.json
vi policy.json

# Policy is automatically reloaded
# Next action uses new policy (within 5 seconds)
This enables dynamic policy adjustment during agent sessions.

Environment Variables

VariableDescriptionExample
AGENT_BROWSER_ACTION_POLICYPath to action policy JSON file./policy.json
AGENT_BROWSER_CONFIRM_ACTIONSComma-separated action categories requiring confirmationeval,download
AGENT_BROWSER_CONFIRM_INTERACTIVEEnable interactive confirmation promptstrue

Configuration File

Set action policy in agent-browser.json:
{
  "actionPolicy": "./policy.json",
  "confirmActions": "eval,download",
  "confirmInteractive": true
}

Programmatic API

Check and enforce action policies programmatically:
import {
  loadPolicyFile,
  checkPolicy,
  getActionCategory,
  describeAction,
  type ActionPolicy,
  type PolicyDecision
} from 'agent-browser/action-policy';

// Load policy from file
const policy: ActionPolicy = loadPolicyFile('./policy.json');
console.log(policy);
// {
//   default: 'deny',
//   allow: ['navigate', 'click', 'fill'],
//   deny: ['eval']
// }

// Check if action is allowed
const confirmCategories = new Set(['download']);
const decision: PolicyDecision = checkPolicy('evaluate', policy, confirmCategories);
console.log(decision); // 'deny' (eval is in deny list)

const decision2 = checkPolicy('click', policy, confirmCategories);
console.log(decision2); // 'allow' (click is in allow list)

const decision3 = checkPolicy('download', policy, confirmCategories);
console.log(decision3); // 'confirm' (download requires confirmation)

// Get action category
const category = getActionCategory('fill');
console.log(category); // 'fill'

const category2 = getActionCategory('dblclick');
console.log(category2); // 'click'

// Describe action for user prompts
const description = describeAction('navigate', { url: 'https://example.com' });
console.log(description); // 'Navigate to https://example.com'

const description2 = describeAction('evaluate', { script: 'console.log("test")' });
console.log(description2); // 'Evaluate JavaScript: console.log("test")'

Auto-reloading Policy

import { initPolicyReloader, reloadPolicyIfChanged } from 'agent-browser/action-policy';

// Initialize reloader
const policy = loadPolicyFile('./policy.json');
initPolicyReloader('./policy.json', policy);

// Check for updates (max once per 5 seconds)
setInterval(() => {
  const updatedPolicy = reloadPolicyIfChanged();
  if (updatedPolicy) {
    console.log('Policy reloaded:', updatedPolicy);
  }
}, 1000);

Best Practices

1. Start with Deny-by-Default

For production agents, use deny-by-default and explicitly allow required actions:
{
  "default": "deny",
  "allow": ["navigate", "click", "fill", "get", "snapshot"]
}

2. Always Deny Eval

JavaScript evaluation is high-risk. Deny it unless absolutely necessary:
{
  "default": "allow",
  "deny": ["eval"]
}
Denying eval also prevents bypassing domain allowlist (see Domain Allowlist).

3. Require Confirmation for Downloads

Prevent data exfiltration by requiring confirmation for downloads:
agent-browser \
  --confirm-actions download \
  --confirm-interactive \
  open example.com

4. Combine with Domain Allowlist

For maximum security, use both action policy and domain allowlist:
agent-browser \
  --allowed-domains "myapp.com,*.myapp.com" \
  --action-policy ./policy.json \
  open https://myapp.com

5. Use Hot Reloading for Testing

During development, use hot reloading to adjust policies without restarting:
# Start browser with policy
agent-browser --action-policy ./policy.json open example.com

# Edit policy.json as needed
# New policy takes effect automatically

Troubleshooting

Action denied by policy

Symptom: Action fails with error like Action 'evaluate' denied by policy Solution: Add the action’s category to the allow list:
{
  "default": "deny",
  "allow": ["navigate", "click", "eval"]
}
Or change default to "allow" and only deny specific categories.

Unrecognized action category warning

Symptom: Warning like unrecognized action category "typo" in policy file Solution: Fix the typo in your policy file. Valid categories are:
  • navigate, click, fill, download, upload, eval, snapshot, scroll, wait, get, network, state, interact

Confirmation prompts in CI/CD

Symptom: Agent hangs waiting for confirmation in CI/CD environment Solution: Don’t use --confirm-interactive in non-interactive environments. Instead, use action policy to deny actions:
{
  "default": "allow",
  "deny": ["eval", "download"]
}

Policy file not found

Symptom: Error like ENOENT: no such file or directory Solution: Ensure the policy file path is correct (relative to current directory):
# Absolute path
agent-browser --action-policy /home/user/policy.json

# Relative path
agent-browser --action-policy ./policy.json

# Or use environment variable
export AGENT_BROWSER_ACTION_POLICY=./policy.json
agent-browser open example.com

See Also

Build docs developers (and LLMs) love