Custom Action
Action Type: Custom
Execute custom logic when a threat is detected. Full control over response behavior.
Available for: All platforms (Desktop, Mobile, Web)
How It Works
The Custom action executes your async delegate when a threat is detected.
Behavior:
- Executes your custom async function
- Complete control over response logic
- Can combine multiple actions (log + close, notify + block, etc.)
- Can make external API calls
- Can implement complex workflows
When to Use
Recommended for:
- Enterprise Integrations - SIEM, SOC, ticketing systems
- Multi-step Workflows - Notify → Confirm → Block → Log
- Notification Systems - Email, Slack, SMS, PagerDuty
- Complex Business Logic - Approval workflows, escalation
- Data Erasure - Secure deletion before shutdown
- Graceful Shutdown - Save state before terminating
- User Interaction - Alerts, confirmation dialogs
Configuration Methods
Method 1: Register and Use in Code
C#
await Payload.ConfigureAsync(config =>
{
// 1. Register the custom action
config.RegisterCustomAction("my-action", async (threat) =>
{
// Your custom logic here
await MySecurityHandler.ProcessAsync(threat);
});
// 2. Assign to protection
config.AddProtection(ProtectionModuleType.DebuggerDetection, "my-action");
});await Payload.ConfigureAsync(config =>
{
// 1. Register the custom action
config.RegisterCustomAction("my-action", async (threat) =>
{
// Your custom logic here
await MySecurityHandler.ProcessAsync(threat);
});
// 2. Assign to protection
config.AddProtection(ProtectionModuleType.DebuggerDetection, "my-action");
});Method 2: Register in Code, Use in JSON
Register your custom actions at application startup:
C#
// Program.cs or Startup
public static async Task Main(string[] args)
{
await Payload.ConfigureAsync(config =>
{
// Register custom actions
config.RegisterCustomAction("notify-security-team", async (threat) =>
{
await emailService.SendAsync("security@company.com",
$"Threat: {threat.Description}");
Environment.Exit(-1);
});
config.RegisterCustomAction("slack-alert", async (threat) =>
{
await slackClient.PostAsync("#security",
$"🚨 {threat.ModuleType}: {threat.Description}");
Environment.Exit(-1);
});
config.RegisterCustomAction("siem-integration", async (threat) =>
{
await siemClient.LogAsync(threat);
Environment.Exit(-1);
});
});
// Application continues...
}// Program.cs or Startup
public static async Task Main(string[] args)
{
await Payload.ConfigureAsync(config =>
{
// Register custom actions
config.RegisterCustomAction("notify-security-team", async (threat) =>
{
await emailService.SendAsync("security@company.com",
$"Threat: {threat.Description}");
Environment.Exit(-1);
});
config.RegisterCustomAction("slack-alert", async (threat) =>
{
await slackClient.PostAsync("#security",
$"🚨 {threat.ModuleType}: {threat.Description}");
Environment.Exit(-1);
});
config.RegisterCustomAction("siem-integration", async (threat) =>
{
await siemClient.LogAsync(threat);
Environment.Exit(-1);
});
});
// Application continues...
}Then reference them in your JSON configuration:
JSON
{
"protections": {
"DebuggerDetection": {
"enabled": true,
"action": "custom",
"customActionName": "notify-security-team"
},
"TamperingDetection": {
"enabled": true,
"action": "custom",
"customActionName": "siem-integration"
},
"JailbreakDetection": {
"enabled": true,
"action": "custom",
"customActionName": "slack-alert"
}
}
}{
"protections": {
"DebuggerDetection": {
"enabled": true,
"action": "custom",
"customActionName": "notify-security-team"
},
"TamperingDetection": {
"enabled": true,
"action": "custom",
"customActionName": "siem-integration"
},
"JailbreakDetection": {
"enabled": true,
"action": "custom",
"customActionName": "slack-alert"
}
}
}Method 3: Hybrid Approach
Register some actions in code, configure others in JSON:
C#
// Startup - Register reusable custom actions
await Payload.ConfigureAsync(config =>
{
config.RegisterCustomAction("email-alert", async (threat) =>
{
await EmailService.SendAlertAsync(threat);
});
config.RegisterCustomAction("pagerduty-alert", async (threat) =>
{
await PagerDutyService.TriggerAsync(threat);
});
});
// Load JSON configuration
await Payload.LoadConfigurationAsync("monitor-config.json");// Startup - Register reusable custom actions
await Payload.ConfigureAsync(config =>
{
config.RegisterCustomAction("email-alert", async (threat) =>
{
await EmailService.SendAlertAsync(threat);
});
config.RegisterCustomAction("pagerduty-alert", async (threat) =>
{
await PagerDutyService.TriggerAsync(threat);
});
});
// Load JSON configuration
await Payload.LoadConfigurationAsync("monitor-config.json");monitor-config.json:
JSON
{
"protections": {
"DebuggerDetection": {
"enabled": true,
"action": "custom",
"customActionName": "email-alert"
},
"MemoryDumpDetection": {
"enabled": true,
"action": "custom",
"customActionName": "pagerduty-alert"
}
}
}{
"protections": {
"DebuggerDetection": {
"enabled": true,
"action": "custom",
"customActionName": "email-alert"
},
"MemoryDumpDetection": {
"enabled": true,
"action": "custom",
"customActionName": "pagerduty-alert"
}
}
}Code Examples
Email Notification
C#
config.RegisterCustomAction("email-security-team", async (threat) =>
{
await emailService.SendAsync(new Email
{
To = "security@company.com",
Subject = $"Security Alert: {threat.ModuleType}",
Body = $@"
Threat Detected: {threat.Description}
Incident ID: {threat.ThreatId}
Time: {DateTime.UtcNow}
Metadata:
{JsonSerializer.Serialize(threat.Metadata, new JsonSerializerOptions { WriteIndented = true })}
"
});
// Then close application
Environment.Exit(-1);
});config.RegisterCustomAction("email-security-team", async (threat) =>
{
await emailService.SendAsync(new Email
{
To = "security@company.com",
Subject = $"Security Alert: {threat.ModuleType}",
Body = $@"
Threat Detected: {threat.Description}
Incident ID: {threat.ThreatId}
Time: {DateTime.UtcNow}
Metadata:
{JsonSerializer.Serialize(threat.Metadata, new JsonSerializerOptions { WriteIndented = true })}
"
});
// Then close application
Environment.Exit(-1);
});SIEM Integration
C#
config.RegisterCustomAction("siem-integration", async (threat) =>
{
// Send to Splunk/ELK/QRadar
await siemClient.SendEventAsync(new SecurityEvent
{
Severity = "Critical",
Type = threat.ModuleType.ToString(),
Description = threat.Description,
ThreatId = threat.ThreatId,
Timestamp = DateTime.UtcNow,
Metadata = threat.Metadata,
HostName = Environment.MachineName,
UserName = Environment.UserName
});
// Log locally
await File.AppendAllTextAsync("logs/security.log",
$"[{DateTime.UtcNow}] {threat.ModuleType}: {threat.Description}\n"
);
// Terminate
Environment.Exit(-1);
});config.RegisterCustomAction("siem-integration", async (threat) =>
{
// Send to Splunk/ELK/QRadar
await siemClient.SendEventAsync(new SecurityEvent
{
Severity = "Critical",
Type = threat.ModuleType.ToString(),
Description = threat.Description,
ThreatId = threat.ThreatId,
Timestamp = DateTime.UtcNow,
Metadata = threat.Metadata,
HostName = Environment.MachineName,
UserName = Environment.UserName
});
// Log locally
await File.AppendAllTextAsync("logs/security.log",
$"[{DateTime.UtcNow}] {threat.ModuleType}: {threat.Description}\n"
);
// Terminate
Environment.Exit(-1);
});Slack Notification
C#
config.RegisterCustomAction("slack-alert", async (threat) =>
{
var slackMessage = new
{
channel = "#security-alerts",
username = "ByteHide Monitor",
icon_emoji = ":shield:",
attachments = new[]
{
new
{
color = "danger",
title = $"Security Threat: {threat.ModuleType}",
text = threat.Description,
fields = new[]
{
new { title = "Incident ID", value = threat.ThreatId, @short = true },
new { title = "Timestamp", value = DateTime.UtcNow.ToString(), @short = true },
new { title = "Machine", value = Environment.MachineName, @short = true },
new { title = "User", value = Environment.UserName, @short = true }
}
}
}
};
await httpClient.PostAsJsonAsync(slackWebhookUrl, slackMessage);
Environment.Exit(-1);
});config.RegisterCustomAction("slack-alert", async (threat) =>
{
var slackMessage = new
{
channel = "#security-alerts",
username = "ByteHide Monitor",
icon_emoji = ":shield:",
attachments = new[]
{
new
{
color = "danger",
title = $"Security Threat: {threat.ModuleType}",
text = threat.Description,
fields = new[]
{
new { title = "Incident ID", value = threat.ThreatId, @short = true },
new { title = "Timestamp", value = DateTime.UtcNow.ToString(), @short = true },
new { title = "Machine", value = Environment.MachineName, @short = true },
new { title = "User", value = Environment.UserName, @short = true }
}
}
}
};
await httpClient.PostAsJsonAsync(slackWebhookUrl, slackMessage);
Environment.Exit(-1);
});Mobile Alert Dialog
C#
config.RegisterCustomAction("mobile-alert", async (threat) =>
{
// Show alert to user
await Application.Current.MainPage.DisplayAlert(
"Security Warning",
$"Threat detected: {threat.Description}\n\nThe application will now close.",
"OK"
);
// Wait for user acknowledgment
await Task.Delay(3000);
// Terminate
Environment.Exit(-1);
});config.RegisterCustomAction("mobile-alert", async (threat) =>
{
// Show alert to user
await Application.Current.MainPage.DisplayAlert(
"Security Warning",
$"Threat detected: {threat.Description}\n\nThe application will now close.",
"OK"
);
// Wait for user acknowledgment
await Task.Delay(3000);
// Terminate
Environment.Exit(-1);
});Conditional Response
C#
config.RegisterCustomAction("conditional-response", async (threat) =>
{
// Different actions based on threat type
switch (threat.ModuleType)
{
case ProtectionModuleType.DebuggerDetection:
// Critical: Close immediately
Environment.Exit(-1);
break;
case ProtectionModuleType.VirtualMachineDetection:
// Medium: Just log
await Logger.LogWarningAsync($"VM detected: {threat.Description}");
break;
case ProtectionModuleType.ClockTampering:
// Low: Show warning but continue
await ShowWarningAsync("System time appears incorrect");
break;
}
});config.RegisterCustomAction("conditional-response", async (threat) =>
{
// Different actions based on threat type
switch (threat.ModuleType)
{
case ProtectionModuleType.DebuggerDetection:
// Critical: Close immediately
Environment.Exit(-1);
break;
case ProtectionModuleType.VirtualMachineDetection:
// Medium: Just log
await Logger.LogWarningAsync($"VM detected: {threat.Description}");
break;
case ProtectionModuleType.ClockTampering:
// Low: Show warning but continue
await ShowWarningAsync("System time appears incorrect");
break;
}
});Grace Period Implementation
C#
config.RegisterCustomAction("grace-period", async (threat) =>
{
var gracePeriodKey = $"grace_{threat.ModuleType}";
var lastDetection = await SecureStorage.GetAsync(gracePeriodKey);
if (DateTime.TryParse(lastDetection, out var lastTime))
{
var daysSince = (DateTime.UtcNow - lastTime).TotalDays;
if (daysSince < 7)
{
var daysRemaining = 7 - (int)daysSince;
await ShowWarningAsync(
"Security Warning",
$"Please address this security issue within {daysRemaining} days."
);
return; // Don't close yet
}
}
// Grace period expired or first detection
await SecureStorage.SetAsync(gracePeriodKey, DateTime.UtcNow.ToString());
await ShowMessageAsync(
"Security Violation",
"The grace period has expired. The application will now close."
);
Environment.Exit(-1);
});config.RegisterCustomAction("grace-period", async (threat) =>
{
var gracePeriodKey = $"grace_{threat.ModuleType}";
var lastDetection = await SecureStorage.GetAsync(gracePeriodKey);
if (DateTime.TryParse(lastDetection, out var lastTime))
{
var daysSince = (DateTime.UtcNow - lastTime).TotalDays;
if (daysSince < 7)
{
var daysRemaining = 7 - (int)daysSince;
await ShowWarningAsync(
"Security Warning",
$"Please address this security issue within {daysRemaining} days."
);
return; // Don't close yet
}
}
// Grace period expired or first detection
await SecureStorage.SetAsync(gracePeriodKey, DateTime.UtcNow.ToString());
await ShowMessageAsync(
"Security Violation",
"The grace period has expired. The application will now close."
);
Environment.Exit(-1);
});User Confirmation
C#
config.RegisterCustomAction("confirm-close", async (threat) =>
{
var result = await Application.Current.MainPage.DisplayAlert(
"Security Threat Detected",
$"{threat.Description}\n\nClose the application?",
"Yes, Close",
"No, Continue"
);
if (result)
{
await Logger.LogAsync($"User confirmed close for {threat.ModuleType}");
Environment.Exit(-1);
}
else
{
await Logger.LogAsync($"User chose to continue despite {threat.ModuleType}");
}
});config.RegisterCustomAction("confirm-close", async (threat) =>
{
var result = await Application.Current.MainPage.DisplayAlert(
"Security Threat Detected",
$"{threat.Description}\n\nClose the application?",
"Yes, Close",
"No, Continue"
);
if (result)
{
await Logger.LogAsync($"User confirmed close for {threat.ModuleType}");
Environment.Exit(-1);
}
else
{
await Logger.LogAsync($"User chose to continue despite {threat.ModuleType}");
}
});Enterprise Workflow
C#
config.RegisterCustomAction("enterprise-workflow", async (threat) =>
{
// 1. Log to database
await dbContext.SecurityIncidents.AddAsync(new SecurityIncident
{
ThreatId = threat.ThreatId,
Type = threat.ModuleType.ToString(),
Description = threat.Description,
Metadata = JsonSerializer.Serialize(threat.Metadata),
DetectedAt = DateTime.UtcNow,
MachineName = Environment.MachineName,
UserName = Environment.UserName
});
await dbContext.SaveChangesAsync();
// 2. Create ticket in ServiceNow
var ticket = await serviceNowClient.CreateIncidentAsync(new
{
short_description = $"Security Threat: {threat.ModuleType}",
description = threat.Description,
severity = "1 - Critical",
assignment_group = "security-operations"
});
// 3. Send to PagerDuty
await pagerDutyClient.TriggerIncidentAsync(new
{
routing_key = pagerDutyKey,
event_action = "trigger",
payload = new
{
summary = $"Security Threat: {threat.ModuleType}",
severity = "critical",
source = Environment.MachineName,
custom_details = threat.Metadata
}
});
// 4. Notify Slack
await slackClient.PostMessageAsync("#security",
$"🚨 Security incident {ticket.Number} created: {threat.Description}"
);
// 5. Log to SIEM
await siemLogger.LogCriticalAsync(threat);
// 6. Terminate application
Environment.Exit(-1);
});config.RegisterCustomAction("enterprise-workflow", async (threat) =>
{
// 1. Log to database
await dbContext.SecurityIncidents.AddAsync(new SecurityIncident
{
ThreatId = threat.ThreatId,
Type = threat.ModuleType.ToString(),
Description = threat.Description,
Metadata = JsonSerializer.Serialize(threat.Metadata),
DetectedAt = DateTime.UtcNow,
MachineName = Environment.MachineName,
UserName = Environment.UserName
});
await dbContext.SaveChangesAsync();
// 2. Create ticket in ServiceNow
var ticket = await serviceNowClient.CreateIncidentAsync(new
{
short_description = $"Security Threat: {threat.ModuleType}",
description = threat.Description,
severity = "1 - Critical",
assignment_group = "security-operations"
});
// 3. Send to PagerDuty
await pagerDutyClient.TriggerIncidentAsync(new
{
routing_key = pagerDutyKey,
event_action = "trigger",
payload = new
{
summary = $"Security Threat: {threat.ModuleType}",
severity = "critical",
source = Environment.MachineName,
custom_details = threat.Metadata
}
});
// 4. Notify Slack
await slackClient.PostMessageAsync("#security",
$"🚨 Security incident {ticket.Number} created: {threat.Description}"
);
// 5. Log to SIEM
await siemLogger.LogCriticalAsync(threat);
// 6. Terminate application
Environment.Exit(-1);
});ASP.NET Core Web Example
C#
builder.Services.AddByteHideMonitor(options =>
{
options.OnThreatDetected = async (httpContext, threat) =>
{
// Log attack details
var attackInfo = new
{
ThreatType = threat.ModuleType.ToString(),
Description = threat.Description,
IpAddress = httpContext.Connection.RemoteIpAddress?.ToString(),
UserAgent = httpContext.Request.Headers["User-Agent"].ToString(),
Path = httpContext.Request.Path,
Method = httpContext.Request.Method,
Timestamp = DateTime.UtcNow
};
await attackLogger.LogAsync(attackInfo);
// Send to security team
await emailService.SendAsync(
"security@company.com",
"Web Attack Blocked",
JsonSerializer.Serialize(attackInfo, new JsonSerializerOptions { WriteIndented = true })
);
// Return custom 403 response
httpContext.Response.StatusCode = 403;
httpContext.Response.Headers["X-Incident-Id"] = threat.ThreatId;
await httpContext.Response.WriteAsJsonAsync(new
{
error = "Security violation detected",
incidentId = threat.ThreatId,
support = "security@company.com"
});
};
});builder.Services.AddByteHideMonitor(options =>
{
options.OnThreatDetected = async (httpContext, threat) =>
{
// Log attack details
var attackInfo = new
{
ThreatType = threat.ModuleType.ToString(),
Description = threat.Description,
IpAddress = httpContext.Connection.RemoteIpAddress?.ToString(),
UserAgent = httpContext.Request.Headers["User-Agent"].ToString(),
Path = httpContext.Request.Path,
Method = httpContext.Request.Method,
Timestamp = DateTime.UtcNow
};
await attackLogger.LogAsync(attackInfo);
// Send to security team
await emailService.SendAsync(
"security@company.com",
"Web Attack Blocked",
JsonSerializer.Serialize(attackInfo, new JsonSerializerOptions { WriteIndented = true })
);
// Return custom 403 response
httpContext.Response.StatusCode = 403;
httpContext.Response.Headers["X-Incident-Id"] = threat.ThreatId;
await httpContext.Response.WriteAsJsonAsync(new
{
error = "Security violation detected",
incidentId = threat.ThreatId,
support = "security@company.com"
});
};
});Threat Object Properties
C#
config.RegisterCustomAction("inspect-threat", async (threat) =>
{
// Available properties:
var threatId = threat.ThreatId; // "DBG-2025-12-28-1234"
var moduleType = threat.ModuleType; // ProtectionModuleType.DebuggerDetection
var description = threat.Description; // "Debugger detected"
var confidence = threat.Confidence; // 0.95
var detectedAt = threat.DetectedAt; // DateTime.UtcNow
var metadata = threat.Metadata; // Dictionary<string, object>
// Metadata examples:
var debuggerName = threat.Metadata["debuggerName"]; // "Visual Studio"
var processId = threat.Metadata["processId"]; // 12345
});config.RegisterCustomAction("inspect-threat", async (threat) =>
{
// Available properties:
var threatId = threat.ThreatId; // "DBG-2025-12-28-1234"
var moduleType = threat.ModuleType; // ProtectionModuleType.DebuggerDetection
var description = threat.Description; // "Debugger detected"
var confidence = threat.Confidence; // 0.95
var detectedAt = threat.DetectedAt; // DateTime.UtcNow
var metadata = threat.Metadata; // Dictionary<string, object>
// Metadata examples:
var debuggerName = threat.Metadata["debuggerName"]; // "Visual Studio"
var processId = threat.Metadata["processId"]; // 12345
});Best Practices
1. Always Handle Exceptions
C#
config.RegisterCustomAction("safe-handler", async (threat) =>
{
try
{
await externalService.NotifyAsync(threat);
}
catch (Exception ex)
{
// Log error but still take security action
await Logger.LogErrorAsync(ex);
}
finally
{
// Always close on critical threats
Environment.Exit(-1);
}
});config.RegisterCustomAction("safe-handler", async (threat) =>
{
try
{
await externalService.NotifyAsync(threat);
}
catch (Exception ex)
{
// Log error but still take security action
await Logger.LogErrorAsync(ex);
}
finally
{
// Always close on critical threats
Environment.Exit(-1);
}
});2. Set Timeouts for External Calls
C#
config.RegisterCustomAction("timeout-handler", async (threat) =>
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
await emailService.SendAsync(threat, cts.Token);
}
catch (OperationCanceledException)
{
// Timeout - close anyway
await Logger.LogAsync("Email notification timed out");
}
Environment.Exit(-1);
});config.RegisterCustomAction("timeout-handler", async (threat) =>
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
await emailService.SendAsync(threat, cts.Token);
}
catch (OperationCanceledException)
{
// Timeout - close anyway
await Logger.LogAsync("Email notification timed out");
}
Environment.Exit(-1);
});3. Don't Block on UI Thread
C#
// Mobile applications
config.RegisterCustomAction("ui-safe", async (threat) =>
{
await Device.InvokeOnMainThreadAsync(async () =>
{
await DisplayAlert("Security Alert", threat.Description, "OK");
});
});// Mobile applications
config.RegisterCustomAction("ui-safe", async (threat) =>
{
await Device.InvokeOnMainThreadAsync(async () =>
{
await DisplayAlert("Security Alert", threat.Description, "OK");
});
});Enterprise Startup Configuration
Register multiple custom actions at startup for use across JSON configurations:
C#
public class Program
{
public static async Task Main(string[] args)
{
// Register all custom actions at startup
await ConfigureMonitorActionsAsync();
var builder = WebApplication.CreateBuilder(args);
// ... rest of app configuration
}
private static async Task ConfigureMonitorActionsAsync()
{
await Payload.ConfigureAsync(config =>
{
// Email notification action
config.RegisterCustomAction("email-security", async (threat) =>
{
await EmailService.SendAsync(new
{
To = "security@company.com",
Subject = $"Security Alert: {threat.ModuleType}",
Body = threat.Description,
Metadata = threat.Metadata
});
Environment.Exit(-1);
});
// Slack notification action
config.RegisterCustomAction("slack-security", async (threat) =>
{
await SlackService.PostAsync("#security-alerts", new
{
text = $"🚨 *{threat.ModuleType}*: {threat.Description}",
incident_id = threat.ThreatId
});
Environment.Exit(-1);
});
// PagerDuty critical alert
config.RegisterCustomAction("pagerduty-critical", async (threat) =>
{
await PagerDutyService.TriggerIncidentAsync(new
{
severity = "critical",
summary = $"Security: {threat.ModuleType}",
details = threat.Metadata
});
Environment.Exit(-1);
});
// SIEM logging action
config.RegisterCustomAction("siem-log", async (threat) =>
{
await SiemService.LogSecurityEventAsync(new
{
event_type = "SecurityThreat",
threat_type = threat.ModuleType.ToString(),
description = threat.Description,
metadata = threat.Metadata,
timestamp = DateTime.UtcNow
});
Environment.Exit(-1);
});
// User notification (mobile)
config.RegisterCustomAction("user-notify", async (threat) =>
{
await Application.Current.MainPage.DisplayAlert(
"Security Warning",
threat.Description,
"OK"
);
await Task.Delay(2000);
Environment.Exit(-1);
});
// Analytics only (no shutdown)
config.RegisterCustomAction("analytics-track", async (threat) =>
{
await AnalyticsService.TrackEventAsync("SecurityThreat", new
{
type = threat.ModuleType.ToString(),
confidence = threat.Confidence,
metadata = threat.Metadata
});
// Don't close - just track
});
});
}
}public class Program
{
public static async Task Main(string[] args)
{
// Register all custom actions at startup
await ConfigureMonitorActionsAsync();
var builder = WebApplication.CreateBuilder(args);
// ... rest of app configuration
}
private static async Task ConfigureMonitorActionsAsync()
{
await Payload.ConfigureAsync(config =>
{
// Email notification action
config.RegisterCustomAction("email-security", async (threat) =>
{
await EmailService.SendAsync(new
{
To = "security@company.com",
Subject = $"Security Alert: {threat.ModuleType}",
Body = threat.Description,
Metadata = threat.Metadata
});
Environment.Exit(-1);
});
// Slack notification action
config.RegisterCustomAction("slack-security", async (threat) =>
{
await SlackService.PostAsync("#security-alerts", new
{
text = $"🚨 *{threat.ModuleType}*: {threat.Description}",
incident_id = threat.ThreatId
});
Environment.Exit(-1);
});
// PagerDuty critical alert
config.RegisterCustomAction("pagerduty-critical", async (threat) =>
{
await PagerDutyService.TriggerIncidentAsync(new
{
severity = "critical",
summary = $"Security: {threat.ModuleType}",
details = threat.Metadata
});
Environment.Exit(-1);
});
// SIEM logging action
config.RegisterCustomAction("siem-log", async (threat) =>
{
await SiemService.LogSecurityEventAsync(new
{
event_type = "SecurityThreat",
threat_type = threat.ModuleType.ToString(),
description = threat.Description,
metadata = threat.Metadata,
timestamp = DateTime.UtcNow
});
Environment.Exit(-1);
});
// User notification (mobile)
config.RegisterCustomAction("user-notify", async (threat) =>
{
await Application.Current.MainPage.DisplayAlert(
"Security Warning",
threat.Description,
"OK"
);
await Task.Delay(2000);
Environment.Exit(-1);
});
// Analytics only (no shutdown)
config.RegisterCustomAction("analytics-track", async (threat) =>
{
await AnalyticsService.TrackEventAsync("SecurityThreat", new
{
type = threat.ModuleType.ToString(),
confidence = threat.Confidence,
metadata = threat.Metadata
});
// Don't close - just track
});
});
}
}Then use in JSON:
JSON
{
"protections": {
"DebuggerDetection": {
"enabled": true,
"action": "custom",
"customActionName": "pagerduty-critical"
},
"SqlInjection": {
"enabled": true,
"action": "custom",
"customActionName": "siem-log"
},
"VirtualMachineDetection": {
"enabled": true,
"action": "custom",
"customActionName": "analytics-track"
},
"JailbreakDetection": {
"enabled": true,
"action": "custom",
"customActionName": "user-notify"
}
}
}{
"protections": {
"DebuggerDetection": {
"enabled": true,
"action": "custom",
"customActionName": "pagerduty-critical"
},
"SqlInjection": {
"enabled": true,
"action": "custom",
"customActionName": "siem-log"
},
"VirtualMachineDetection": {
"enabled": true,
"action": "custom",
"customActionName": "analytics-track"
},
"JailbreakDetection": {
"enabled": true,
"action": "custom",
"customActionName": "user-notify"
}
}
}Benefits of Register-in-Code + JSON Configuration
- Separation of Concerns: Business logic in code, configuration in JSON
- Environment-Specific Config: Different JSON files per environment
- Non-Developer Changes: Ops team can adjust without code changes
- Reusable Actions: Register once, use across multiple protections
- Type Safety: C# type checking for action implementation
- Easy Testing: Test custom actions independently
Related Actions
- Close - Simple termination
- Erase - Secure data deletion
- Log - Simple logging
- Block - Web request blocking
All Actions
View all action types
Custom Actions Guide
Advanced examples