Custom Actions
Unified Security Stack comes with 73 built-in action templates, yet you can build fully custom actions for scenarios unique to your environment. Custom actions enable you to run any shell command, call external APIs, execute scripts, or work with third-party tools, with SOAR workflows triggering all of it automatically.
When to Use Custom Actions
Use custom actions when:
No built-in template covers your use case
You need to integrate with a third-party tool (ITSM, ticketing, SOAR platforms, cloud APIs)
You want to run a custom script or automation specific to your infrastructure
You need to chain multiple commands that don't fit a single template
You want to call REST APIs from the endpoint (e.g., notify a Slack channel, create a Jira ticket, update a CMDB)
Creating a Custom Action
In the workflow builder, click the Define Custom Action card located at the bottom of the left panel's action sidebar.
The custom action editor opens with three fields:
| Field | Requirement | Description |
|---|---|---|
| Action Name | Min 5 characters | A descriptive name for the action |
| Description | Min 5 characters | What the action does |
| Command | Required | The shell command to execute |
Writing the Command
The command editor is a terminal-style text field. You enter the exact shell command to be executed on the target agent.
For Windows agents, the command runs in the shell selected for the workflow (CMD or PowerShell):
# PowerShell example: Query Active Directory for a compromised user
Get-ADUser -Identity $(adversary.user) -Properties LockedOut,Enabled,LastLogonDate | Format-List# CMD example: Add a persistent firewall rule
netsh advfirewall firewall add rule name="Block-$(adversary.ip)" dir=in action=block remoteip="$(adversary.ip)" enable=yesFor Linux/macOS agents, the command runs in Bash:
# Block an IP and log the action
iptables -A INPUT -s $(adversary.ip) -j DROP && echo "$(date): Blocked $(adversary.ip) from alert $(name)" >> /var/log/soar-actions.logInserting Dynamic Variables
While typing in the command editor, press TAB to bring up the variable picker. Two categories are provided:
Alert Fields — Values extracted from the triggering alert:
$(adversary.ip)— Attacker IP address$(adversary.user)— Attacker username$(target.user)— Victim username$(adversary.process)— Suspicious process path$(log.message)— Raw log message$(name)— Alert name$(severity)— Alert severity levelAnd 50+ additional fields covering adversary/target geolocation, network, file, hash, and system data
Click any field to insert it at the cursor position within the command.
Automation Variables — Reusable values you define in SOAR > Automation Variables:
Referenced as
$[variables.variableName]Regular variables — stored in plain text, visible in logs
Secret variables — encrypted at rest, decrypted only at execution time on the agent, masked in all logs
Examples of Custom Actions
Call a REST API to create an incident ticket
curl -sk -X POST \"https://itsm.example.com/api/incidents\"
-H \"Authorization: Bearer $[variables.itsmApiKey]\"
-H \"Content-Type: application/json\"
-d '{\"title\": \"SOAR Alert: $(name)\", \"severity\": \"$(severity)\", \"source_ip\": \"$(adversary.ip)\", \"description\": \"Automated incident from Unified Security Stack alert\"}'Send a Slack notification
curl -sk -X POST \"https://hooks.slack.com/services/$[variables.slackWebhook]\"
-H \"Content-Type: application/json\"
-d '{\"text\": \"SOAR Alert: $(name) detected from $(adversary.ip) targeting $(target.user). Severity: $(severity)\"}'Run a custom Python script
python3 /opt/soar-scripts/remediate.py --alert-name \"$(name)\" --source-ip \"$(adversary.ip)\" --target-user \"$(target.user)\"Block an IP on a remote firewall via SSH (using proxy agent)
ssh -o StrictHostKeyChecking=no -i $[variables.fwSshKey] admin@$[variables.firewallIp] \"set security address-book global address blocked-$(adversary.ip) $(adversary.ip)/32 && commit\"Query VirusTotal for a file hash
curl -sk \"https://www.virustotal.com/api/v3/files/$(adversary.filehash)\"
-H \"x-apikey: $[variables.vtApiKey]\"
| python3 -c \"import sys,json; d=json.load(sys.stdin); print('Malicious' if d['data']['attributes']['last_analysis_stats']['malicious'] > 5 else 'Clean')\"Windows: Quarantine a file and log the action
$path = \"$(adversary.path)\"; $quarantine = \"C:\\Quarantine\\$(Get-Date -Format yyyyMMdd_HHmmss)\"; New-Item -ItemType Directory -Path $quarantine -Force; Move-Item -Path $path -Destination $quarantine -Force; Add-Content -Path \"C:\\Quarantine\\quarantine.log\" -Value \"$(Get-Date): Quarantined $path to $quarantine from alert $(name)\"Saving Custom Actions as Templates
Once you create a custom action inside a workflow, it becomes part of that workflow's action sequence. To reuse the same custom action in multiple workflows, you can:
Create the custom action in one workflow and save the workflow
In subsequent workflows, recreate the action with the same command, or copy the workflow and modify the trigger
For commands you use often, maintain a documented library of tested command templates. This lets you easily copy them into new workflows without testing them again.
Security Considerations
Custom actions run with the privileges of the Unified Security Stack agent on the target system. Be careful with:
Destructive commands (rm -rf, format, shutdown) — always test in a non-production environment first
Secret exposure — never use echo/print/cat to display secret variable values. The system blocks commands that try to expose secrets.
Injection risks — dynamic variables are inserted exactly as provided. If an attacker can control a field value, such as a crafted hostname, the command could be manipulated. Validate inputs when you build complex commands.
Network access — commands that call external APIs require the agent to have outbound network access to those endpoints"}