No description
  • TypeScript 100%
Find a file
2026-03-22 07:02:50 -03:00
src Initial commit 2026-03-22 07:02:50 -03:00
tests Initial commit 2026-03-22 07:02:50 -03:00
.gitignore Initial commit 2026-03-22 07:02:50 -03:00
package-lock.json Initial commit 2026-03-22 07:02:50 -03:00
package.json Initial commit 2026-03-22 07:02:50 -03:00
README.md Initial commit 2026-03-22 07:02:50 -03:00
security-permissions.example.json Initial commit 2026-03-22 07:02:50 -03:00
tsconfig.json Initial commit 2026-03-22 07:02:50 -03:00

Security Permissions Plugin

A standalone, headless security plugin for Fractal Synapse agents that audits every tool call before execution. Enforces three dimensions of access control from a security-permissions.json file: tool-level permissions, file system path permissions, and bash command permissions.

When a permission is denied the tool call is aborted gracefully — the LLM receives the denial as a tool error and can adapt (explain the restriction, try a different approach, etc.) without crashing the agent loop.

Features

  • Tool permissions — allow or deny specific tools entirely (e.g. block bash outright)
  • Path permissions — allow or deny file system paths with prefix matching (longest match wins)
  • Bash command permissions — allow or deny bash commands by pattern, with subcommand splitting (cd /safe && rm -rf / checks cd and rm independently — deny wins)
  • Inline path detection — scans bash command strings for embedded paths (cat /etc/passwd)
  • Cross-platform path normalization — Windows, Unix, and Unix-style drive paths all compared correctly
  • Self-protecting — the permissions file itself is hardcoded-off-limits to the agent; cannot be overridden by any rule
  • Parent directory protection — blocks deletion of any directory containing the permissions file
  • Hot reload — optional interval-based reload for development; preserves current rules if the file is missing or invalid
  • Graceful degradation — runs in defaultBehavior-only mode when no storage plugin is found

Installation

npm install @fractal-synapse/security-permissions

Usage

Basic Setup

import { SecurityPermissionsPlugin } from '@fractal-synapse/security-permissions';

const securityPlugin = new SecurityPermissionsPlugin({
  defaultBehavior: 'allow'  // 'allow' | 'deny' — applied when no rule matches
});

const pluginRegistry = new PluginRegistry();
pluginRegistry.register(securityPlugin);  // Register first — must run before other plugins

const agent = new Agent({
  agentDefinition: new AgentDefinition(
    'My Agent', 'Description', 'System prompt', [],
    'anthropic-claude-sonnet',
    ['security-permissions', 'storage-fs']  // security-permissions must be listed first
  ),
  pluginRegistry
});

Permissions File

Place security-permissions.json in the agent's storage directory:

  • Windows: %LOCALAPPDATA%\FractalSynapse\<app-name>\security-permissions.json
  • macOS: ~/Library/Application Support/FractalSynapse/<app-name>/security-permissions.json
  • Linux: ~/.fractal-synapse/<app-name>/security-permissions.json

The plugin logs the resolved storage path on initialization so you know where to place the file.

{
  "version": 1,
  "defaultBehavior": "deny",
  "tools": {
    "bash": "allow",
    "edit-file": "allow",
    "create-file": "allow",
    "read-file": "allow",
    "list-files": "allow"
  },
  "paths": [
    { "path": "/home/user/projects/myapp", "permission": "allow" },
    { "path": "/etc", "permission": "deny" },
    { "path": "/home/user/.ssh", "permission": "deny" }
  ],
  "commands": [
    { "pattern": "ls", "permission": "allow" },
    { "pattern": "cat", "permission": "allow" },
    { "pattern": "grep", "permission": "allow" },
    { "pattern": "git", "permission": "allow" },
    { "pattern": "npm", "permission": "allow" },
    { "pattern": "rm", "permission": "deny" },
    { "pattern": "curl", "permission": "deny" },
    { "pattern": "wget", "permission": "deny" },
    { "pattern": "sudo", "permission": "deny" }
  ]
}

See security-permissions.example.json in this package for a ready-to-copy template.

Rule Evaluation Order

For each tool call, rules are evaluated in this order — first match wins:

  1. Hardcoded self-protection — deny any access to the permissions file or its parent directory (unconditional, cannot be overridden)
  2. Tool rule — check if the tool name has an explicit allow/deny rule
  3. Path rules — check named path args (longest prefix match wins)
  4. Bash inline paths — scan the command string for embedded path tokens
  5. Command rules — split on &&, ||, ;, | and check each subcommand; deny wins
  6. defaultBehavior — applied if no rule matched

Configuration

new SecurityPermissionsPlugin({
  defaultBehavior?: 'allow' | 'deny';  // Default: 'deny'
  permissionsFile?: string;            // Filename in storage dir. Default: 'security-permissions.json'
  hotReload?: boolean;                 // Reload file on interval. Default: false
  hotReloadInterval?: number;          // Interval in ms when hotReload is true. Default: 5000
})

Hot Reload

When hotReload: true, the plugin polls the permissions file every hotReloadInterval ms and applies any changes immediately. If the file is missing or invalid at reload time, the current rules stay active and an error is logged — the agent is never left unprotected.

Intended for development and debugging. Disable in production once human-middleware or other runtime controls are in place.

const securityPlugin = new SecurityPermissionsPlugin({
  defaultBehavior: 'allow',
  hotReload: true,
  hotReloadInterval: 3000  // check every 3 seconds
});

Security Model

What this plugin enforces

  • Named path arguments in fs tools (filePath, directoryPath, workingDirectory)
  • Embedded paths in bash command strings (cat /etc/passwd, cd /safe && rm /unsafe)
  • Bash command patterns, evaluated per subcommand in chained commands
  • The permissions file itself — always protected, regardless of rules

Known limitations (v1)

  • Quoted paths containing spaces in bash commands are not extracted
  • Environment variable expansion ($HOME/secret) is not resolved before path checking
  • The ask permission value is reserved for future human-middleware integration; currently treated as deny

API Reference

Constructor

new SecurityPermissionsPlugin(config?: SecurityPermissionsConfig)

Runtime Rule Management

These methods update rules in memory and persist them to storage. Intended for future human-middleware integration.

addPathRule(path: string, permission: 'allow' | 'deny'): Promise<void>
addToolRule(toolName: string, permission: 'allow' | 'deny'): Promise<void>
addCommandRule(pattern: string, permission: 'allow' | 'deny'): Promise<void>
getData(): PermissionsData

Requirements

  • @fractal-synapse/agent-core — core agent functionality and before-tool hook
  • @fractal-synapse/storage-fs (or another storage plugin) — for loading the permissions file

License

ISC