Skip to main content

Cyberstrike is now open source! AI-powered penetration testing for security professionals. Star on GitHub

Hooks System

Hooks allow you to extend and customize Cyberstrike behavior at key points during execution. The system supports two types of hooks: plugin hooks for deep integration and config-based hooks for simple shell command execution.

🎬 GIF: g10-hook-blocking.gif

Hook tehlikeli komutu engellerken (12s)

📸 SCREENSHOT: s14-hook-block.png

Hook engelleme mesajı

Hook Types

TypePurposeConfiguration
Plugin HooksDeep integration with TypeScriptPlugin package
Config HooksShell command executioncyberstrike.json

Plugin Hooks

Plugin hooks provide programmatic access to Cyberstrike internals. Create plugins using the @cyberstrike-io/plugin package.

Available Plugin Hooks

HookTriggerUse Case
tool.execute.beforeBefore tool executionModify arguments, add logging
tool.execute.afterAfter tool executionTransform output, send notifications
permission.askPermission requestedCustom approval logic
chat.messageNew message receivedMessage preprocessing
chat.paramsLLM call preparedModify temperature, add options
chat.headersHTTP request preparedAdd custom headers
command.execute.beforeSlash command invokedInject context
eventAny bus eventAnalytics, logging
configConfiguration loadedDynamic config modification

Hook Execution Flow

sequenceDiagram
participant User
participant Agent
participant Hook System
participant Tool
User->>Agent: Request action
Agent->>Hook System: tool.execute.before
Hook System-->>Agent: Modified args
Agent->>Tool: Execute with args
Tool-->>Agent: Raw output
Agent->>Hook System: tool.execute.after
Hook System-->>Agent: Transformed output
Agent-->>User: Final response

Creating a Plugin

Plugin Structure

my-plugin/index.ts
import type { Plugin, Hooks } from "@cyberstrike-io/plugin"
export const myPlugin: Plugin = async (input) => {
const { client, project, directory } = input
const hooks: Hooks = {
// Pre-tool execution hook
"tool.execute.before": async (input, output) => {
console.log(`Tool ${input.tool} called with:`, output.args)
// Modify args if needed
if (input.tool === "Bash" && output.args.command.includes("rm")) {
output.args.command = `echo "Blocked: ${output.args.command}"`
}
},
// Post-tool execution hook
"tool.execute.after": async (input, output) => {
console.log(`Tool ${input.tool} completed:`, output.title)
// Transform output if needed
},
// Permission hook
"permission.ask": async (input, output) => {
// Auto-approve read operations
if (input.tool === "Read") {
output.status = "allow"
}
// Block dangerous patterns
if (input.command?.includes("--force")) {
output.status = "deny"
}
},
// Event listener
event: async ({ event }) => {
// Log all events to external service
await fetch("https://analytics.example.com/event", {
method: "POST",
body: JSON.stringify(event),
})
},
}
return hooks
}
export default myPlugin

Plugin Input

The plugin receives context about the current environment:

PropertyTypeDescription
clientCyberstrikeClientSDK client instance
projectProjectCurrent project info
directorystringWorking directory
worktreestringGit worktree path
serverUrlURLLocal server URL
$BunShellBun shell for commands

Pre-Tool Hook (tool.execute.before)

Intercept tool calls before execution to modify arguments or block execution.

Hook Signature

"tool.execute.before": async (
input: {
tool: string // Tool name (Bash, Read, Write, etc.)
sessionID: string // Current session ID
callID: string // Unique call identifier
},
output: {
args: any // Tool arguments (mutable)
}
) => Promise<void>

Examples

Logging All Tool Calls

"tool.execute.before": async (input, output) => {
const timestamp = new Date().toISOString()
console.log(`[${timestamp}] ${input.tool}:`, JSON.stringify(output.args))
}

Blocking Dangerous Commands

"tool.execute.before": async (input, output) => {
if (input.tool !== "Bash") return
const dangerous = ["rm -rf", "mkfs", "dd if=", "> /dev/"]
const command = output.args.command
for (const pattern of dangerous) {
if (command.includes(pattern)) {
throw new Error(`Blocked dangerous command: ${pattern}`)
}
}
}

Modifying Arguments

"tool.execute.before": async (input, output) => {
if (input.tool === "Bash") {
// Add safety flags to git commands
if (output.args.command.startsWith("git push")) {
output.args.command = output.args.command.replace(
"git push",
"git push --dry-run"
)
}
}
}

Post-Tool Hook (tool.execute.after)

Process tool output after execution for transformation or notification.

Hook Signature

"tool.execute.after": async (
input: {
tool: string // Tool name
sessionID: string // Current session ID
callID: string // Unique call identifier
},
output: {
title: string // Output title
output: string // Tool output (mutable)
metadata: any // Additional metadata
}
) => Promise<void>

Examples

Redacting Sensitive Data

"tool.execute.after": async (input, output) => {
// Redact API keys from output
output.output = output.output.replace(
/sk-[a-zA-Z0-9]{32,}/g,
"[REDACTED]"
)
// Redact passwords
output.output = output.output.replace(
/password[=:]\s*\S+/gi,
"password=[REDACTED]"
)
}

Sending Notifications

"tool.execute.after": async (input, output) => {
// Notify on file writes
if (input.tool === "Write") {
await sendSlackNotification({
channel: "#code-changes",
message: `File written: ${output.title}`,
})
}
}

Permission Hook (permission.ask)

Customize permission decisions programmatically.

Hook Signature

"permission.ask": async (
input: Permission, // Permission request details
output: {
status: "ask" | "deny" | "allow" // Decision (mutable)
}
) => Promise<void>

Examples

Auto-Approve Safe Operations

"permission.ask": async (input, output) => {
const safeTools = ["Read", "Glob", "Grep", "LSP"]
if (safeTools.includes(input.tool)) {
output.status = "allow"
return
}
// Allow writes to test directories
if (input.tool === "Write" && input.path?.includes("/test/")) {
output.status = "allow"
}
}

Deny Specific Patterns

"permission.ask": async (input, output) => {
// Block access to sensitive directories
const sensitive = [".env", "credentials", "secrets", ".ssh"]
if (input.path) {
for (const dir of sensitive) {
if (input.path.includes(dir)) {
output.status = "deny"
return
}
}
}
}

Chat Hooks

Modify LLM interactions before requests are sent.

chat.message

Preprocess incoming messages:

"chat.message": async (input, output) => {
const { sessionID, agent, model } = input
// Add context to message parts
output.parts.push({
type: "text",
text: `[Session: ${sessionID}, Agent: ${agent}]`,
})
}

chat.params

Modify LLM parameters:

"chat.params": async (input, output) => {
// Use lower temperature for code generation
if (input.agent === "build") {
output.temperature = 0.3
}
// Use higher temperature for creative tasks
if (input.agent === "plan") {
output.temperature = 0.8
}
}

chat.headers

Add custom HTTP headers:

"chat.headers": async (input, output) => {
output.headers["X-Custom-Header"] = "value"
output.headers["X-Session-ID"] = input.sessionID
}

Config-Based Hooks

For simple shell command execution, use config-based hooks in cyberstrike.json.

file_edited Hook

Execute commands when specific files are edited:

cyberstrike.json
{
"experimental": {
"hook": {
"file_edited": {
"*.ts": [
{
"command": ["npx", "eslint", "--fix", "$FILE"],
"environment": {
"NODE_ENV": "development"
}
}
],
"*.py": [
{
"command": ["black", "$FILE"]
},
{
"command": ["ruff", "check", "--fix", "$FILE"]
}
],
"*.go": [
{
"command": ["gofmt", "-w", "$FILE"]
}
]
}
}
}
}

Hook Variables

VariableDescription
$FILEFull path to the edited file

session_completed Hook

Execute commands when a session ends:

cyberstrike.json
{
"experimental": {
"hook": {
"session_completed": [
{
"command": ["git", "status"],
"environment": {}
},
{
"command": ["./scripts/post-session-cleanup.sh"]
}
]
}
}
}

Installing Plugins

From npm

Add plugins to your configuration:

cyberstrike.json
{
"plugin": [
]
}

From Local File

Reference local plugin files:

cyberstrike.json
{
"plugin": [
"file:///path/to/my-plugin"
]
}

Built-in Plugins

Cyberstrike includes built-in plugins for authentication:

PluginPurpose
cyberstrike-anthropic-authAnthropic OAuth
@gitlab/cyberstrike-gitlab-authGitLab integration

Authentication Hooks

Create custom authentication providers:

const authHook: AuthHook = {
provider: "my-provider",
methods: [
{
type: "api",
label: "API Key",
prompts: [
{
type: "text",
key: "apiKey",
message: "Enter your API key",
placeholder: "sk-...",
validate: (value) => {
if (!value.startsWith("sk-")) {
return "API key must start with sk-"
}
},
},
],
authorize: async (inputs) => {
const valid = await validateKey(inputs.apiKey)
if (valid) {
return { type: "success", key: inputs.apiKey }
}
return { type: "failed" }
},
},
{
type: "oauth",
label: "OAuth Login",
authorize: async () => ({
url: "https://auth.example.com/oauth",
instructions: "Complete login in browser",
method: "auto",
callback: async () => {
// Handle OAuth callback
return { type: "success", key: "obtained-key" }
},
}),
},
],
}

Custom Tool Hooks

Add custom tools through plugins:

const hooks: Hooks = {
tool: {
my_scanner: {
description: "Custom vulnerability scanner",
parameters: {
type: "object",
properties: {
target: {
type: "string",
description: "Target URL to scan",
},
depth: {
type: "number",
description: "Scan depth",
default: 3,
},
},
required: ["target"],
},
execute: async (args, context) => {
const result = await runScanner(args.target, args.depth)
return {
output: result,
title: `Scanned ${args.target}`,
}
},
},
},
}

Best Practices

Performance

  1. Keep hooks lightweight to avoid latency
  2. Use async operations for external calls
  3. Cache expensive computations
  4. Avoid blocking the main thread

Security

  1. Validate all inputs in hooks
  2. Sanitize outputs before returning
  3. Use environment variables for secrets
  4. Log security-relevant events

Debugging

Enable plugin logging:

Terminal window
CYBERSTRIKE_LOG_LEVEL=debug cyberstrike

View plugin loading:

[plugin] loading plugin [email protected]
[plugin] loading internal plugin CodexAuthPlugin

Troubleshooting

Plugin Not Loading

  1. Check plugin path or npm package name
  2. Verify plugin exports a valid Plugin function
  3. Check for TypeScript compilation errors

Hook Not Triggering

  1. Verify hook name matches exactly
  2. Check that plugin is listed in configuration
  3. Enable debug logging to trace execution

Performance Issues

  1. Profile hook execution time
  2. Move heavy operations to background
  3. Consider caching frequent operations

Caution

Config-based hooks are experimental. The API may change in future releases.