Skip to main content

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

Creating Plugins

Learn how to create, test, and publish plugins that extend Cyberstrike’s functionality.

📸 SCREENSHOT: plugin-development.png

Plugin development workflow

Getting Started

Create Plugin Project

Terminal window
mkdir cyberstrike-plugin-myname
cd cyberstrike-plugin-myname
npm init -y

Install Dependencies

Terminal window
npm install @cyberstrike/plugin typescript
npm install -D @types/node

Configure TypeScript

tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"declaration": true,
"outDir": "dist",
"strict": true
},
"include": ["src/**/*"]
}

Configure Package

package.json
{
"name": "cyberstrike-plugin-security-checks",
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"test": "vitest"
},
"cyberstrike": {
"plugin": true
},
"peerDependencies": {
"@cyberstrike/plugin": "^1.0.0"
},
"keywords": [
"cyberstrike",
"cyberstrike-plugin",
"security"
]
}

Plugin Interface

Basic Plugin

src/index.ts
import {
CyberstrikePlugin,
ToolHook,
PluginContext
} from '@cyberstrike/plugin';
export default class MyPlugin implements CyberstrikePlugin {
name = 'my-plugin';
version = '1.0.0';
description = 'My custom Cyberstrike plugin';
// Optional initialization
async initialize(context: PluginContext): Promise<void> {
console.log('Plugin initialized');
}
// Optional cleanup
async destroy(): Promise<void> {
console.log('Plugin destroyed');
}
// Hook definitions
hooks: ToolHook[] = [
{
event: 'preToolUse',
matcher: 'Bash',
handler: this.validateCommand.bind(this)
}
];
private async validateCommand(context: PreToolUseContext) {
// Implementation
return { action: 'continue' };
}
}

Plugin with Options

import { CyberstrikePlugin, PluginOptions } from '@cyberstrike/plugin';
interface MyPluginOptions extends PluginOptions {
strictMode?: boolean;
allowedCommands?: string[];
logLevel?: 'debug' | 'info' | 'warn' | 'error';
}
export default class MyPlugin implements CyberstrikePlugin {
name = 'my-plugin';
version = '1.0.0';
private options: MyPluginOptions;
constructor(options: MyPluginOptions = {}) {
this.options = {
strictMode: false,
allowedCommands: [],
logLevel: 'info',
...options
};
}
async initialize(context: PluginContext): Promise<void> {
if (this.options.strictMode) {
this.enableStrictMode();
}
}
// ... rest of implementation
}

Hook Implementation

PreToolUse Hook

import { PreToolUseContext, HookResult } from '@cyberstrike/plugin';
async function validateCommand(
context: PreToolUseContext
): Promise<HookResult> {
const { tool, args, sessionId } = context;
// Validate
if (isDangerous(args.command)) {
return {
action: 'block',
message: 'Dangerous command blocked by security policy'
};
}
// Modify arguments
if (needsSanitization(args.command)) {
return {
action: 'continue',
args: {
...args,
command: sanitize(args.command)
}
};
}
// Continue normally
return { action: 'continue' };
}

PostToolUse Hook

import { PostToolUseContext, HookResult } from '@cyberstrike/plugin';
async function logToolUsage(
context: PostToolUseContext
): Promise<HookResult> {
const { tool, args, result, duration } = context;
await logger.log({
timestamp: new Date(),
tool,
args,
success: result.success,
duration
});
// Optionally modify result
if (containsSensitiveData(result.output)) {
return {
action: 'continue',
result: {
...result,
output: redactSensitiveData(result.output)
}
};
}
return { action: 'continue' };
}

Session Hooks

import { SessionContext } from '@cyberstrike/plugin';
async function onSessionStart(context: SessionContext): Promise<void> {
// Initialize session-specific state
await database.createSession(context.sessionId);
}
async function onSessionEnd(context: SessionContext): Promise<void> {
// Cleanup and reporting
await generateSessionReport(context.sessionId);
await database.closeSession(context.sessionId);
}

State Management

Plugin State

export default class StatefulPlugin implements CyberstrikePlugin {
name = 'stateful-plugin';
version = '1.0.0';
private state: Map<string, any> = new Map();
hooks = [
{
event: 'preToolUse',
matcher: '*',
handler: async (context) => {
// Track tool usage
const count = this.state.get('toolCount') || 0;
this.state.set('toolCount', count + 1);
return { action: 'continue' };
}
}
];
getToolCount(): number {
return this.state.get('toolCount') || 0;
}
}

Persistent State

import fs from 'fs/promises';
export default class PersistentPlugin implements CyberstrikePlugin {
name = 'persistent-plugin';
version = '1.0.0';
private statePath = '/tmp/cyberstrike-plugin-state.json';
private state: Record<string, any> = {};
async initialize(): Promise<void> {
try {
const data = await fs.readFile(this.statePath, 'utf-8');
this.state = JSON.parse(data);
} catch {
this.state = {};
}
}
async destroy(): Promise<void> {
await fs.writeFile(
this.statePath,
JSON.stringify(this.state, null, 2)
);
}
}

Testing

Unit Tests

src/__tests__/plugin.test.ts
import { describe, it, expect, vi } from 'vitest';
import MyPlugin from '../index';
describe('MyPlugin', () => {
it('should block dangerous commands', async () => {
const plugin = new MyPlugin();
const context = {
tool: 'Bash',
args: { command: 'rm -rf /' },
sessionId: 'test-session'
};
const result = await plugin.hooks[0].handler(context);
expect(result.action).toBe('block');
expect(result.message).toContain('dangerous');
});
it('should allow safe commands', async () => {
const plugin = new MyPlugin();
const context = {
tool: 'Bash',
args: { command: 'ls -la' },
sessionId: 'test-session'
};
const result = await plugin.hooks[0].handler(context);
expect(result.action).toBe('continue');
});
});

Integration Tests

src/__tests__/integration.test.ts
import { createTestClient } from '@cyberstrike/plugin/testing';
import MyPlugin from '../index';
describe('MyPlugin Integration', () => {
it('should integrate with Cyberstrike', async () => {
const client = await createTestClient({
plugins: [new MyPlugin()]
});
// Test plugin behavior
const result = await client.executeTool('Bash', {
command: 'echo "hello"'
});
expect(result.success).toBe(true);
});
});

Local Development

Terminal window
# In plugin directory
npm link
# In test project
npm link cyberstrike-plugin-myname

Configure for Testing

cyberstrike.json
{
"plugins": [
"cyberstrike-plugin-myname"
]
}

Watch Mode

Terminal window
npm run dev
# Plugin reloads on changes

Publishing

Prepare for Publish

  1. Update version in package.json
  2. Update CHANGELOG.md
  3. Build the plugin
  4. Run tests

Publish to npm

Terminal window
npm run build
npm test
npm publish --access public

Plugin Naming

Follow the convention:

  • cyberstrike-plugin-<name>
  • @org/cyberstrike-plugin-<name>

Documentation

README Template

# cyberstrike-plugin-security-checks
Security validation plugin for Cyberstrike.
## Installation
\`\`\`bash
npm install cyberstrike-plugin-security-checks
\`\`\`
## Configuration
\`\`\`json
{
"plugins": [
{
"name": "cyberstrike-plugin-security-checks",
"options": {
"strictMode": true
}
}
]
}
\`\`\`
## Features
- Blocks dangerous commands
- Validates file operations
- Logs security events
## Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| strictMode | boolean | false | Enable strict validation |
## License
MIT

Best Practices

  1. Single responsibility - One plugin, one purpose
  2. Fast execution - Don’t block unnecessarily
  3. Error handling - Handle all error cases
  4. Type safety - Use TypeScript
  5. Documentation - Document all features
  6. Testing - Comprehensive test coverage
  7. Versioning - Follow semver

Tip

Start with a simple plugin that does one thing well, then expand functionality.