While Splunk SOAR provides many visual tools and built-in integrations, custom coding lets you go beyond what’s available out of the box.
It gives you full control over:
Data parsing
Decision-making
Custom workflows
Integrating with systems that don’t have native SOAR apps
If you can write it in Python, you can likely automate it in SOAR.
There are three main ways to use custom code in SOAR:
Custom Functions are Python scripts you can build once and use in multiple playbooks.
Accept inputs (like a list of IPs or strings).
Perform a task (e.g., normalize data, calculate scores).
Return structured output (typically a dictionary or JSON).
A function that takes a list of domain names and extracts only the top-level domains (TLDs).
Output: a list like [".com", ".net", ".org"]
Reusable across teams.
Easy to maintain and version.
Promotes clean modular design.
Ideal for logic that doesn’t belong to a specific app or asset.
These are Python scripts embedded directly in a visual playbook using the Code Block node.
Perform string operations.
Loop through a list of artifacts.
Filter out unwanted items.
Format data in a custom way.
Log variables for debugging.
for ip in ip_list:
if ip.startswith("192.168"):
internal_ips.append(ip)
Code blocks give you fine-grained control over data within a playbook.
If SOAR doesn’t have an app for a specific tool, you can build your own app from scratch using Python.
YAML Metadata File:
Python Action Handlers:
Implement the actual code for each action.
Often use REST API requests to external systems.
Optional REST Endpoints:
Expose parts of your app as a callable API.
Can be used by other systems or internal SOAR tools.
Apps are best for full integrations that need to be reused across the platform.
Here’s how custom coding enhances SOAR capabilities:
Example: Extract a username from a log entry like "[email protected]"
Or format time values, remove special characters, etc.
When visual filters aren’t enough, Python can clean and reshape your data exactly how you want.
Visual decision blocks are powerful, but they can be limited.
Python lets you:
Run loops
Handle multiple conditions
Create fallback logic or retry strategies
More flexible than drag-and-drop logic.
Some internal tools or third-party APIs don’t have official SOAR apps.
Use Python to:
Send API requests
Parse custom formats (XML, YAML, etc.)
Handle authentication (OAuth, tokens)
Python bridges the gap where native support is missing.
To write secure, maintainable code in SOAR, follow these tips:
Avoid code injection by cleaning input.
Never trust external values without checking or escaping them.
Especially important when using user input, file paths, or unverified data.
phantom.debug() to log values and variables:phantom.debug("Score is: {}".format(score))
Use logging generously when testing or troubleshooting.
Splunk provides clear developer documentation for:
Custom app development
Code standards
YAML schema
Use the official SDK and templates to build apps faster and more reliably.
Proper use of SDK tools reduces bugs and improves performance.
| Component | Purpose & Use |
|---|---|
| Custom Functions | Reusable Python scripts used across multiple playbooks |
| Playbook Scripts | Logic blocks embedded directly into visual playbooks |
| App Development | Full Python integrations using YAML + API logic |
| Use Case: Parsing | Clean and structure data not handled by visual filters |
| Use Case: Logic | Complex decision-making beyond drag-and-drop tools |
| Use Case: Integration | Connect to tools without official Splunk SOAR apps |
| Best Practices | Sanitize input, use debug logging, follow SDK guidelines |
Custom Functions in Splunk SOAR are reusable Python components that enable teams to encapsulate logic and share it across multiple playbooks.
Defining Input Parameters:
Inputs are declared as part of the function metadata.
You can specify:
Type (string, list, integer, boolean)
Required or optional
Array support (e.g., ["ip1", "ip2"])
Input validation can be implemented in code if needed.
Returning Output:
The function must return a Python dictionary.
Best practice: return consistent, structured keys so the output can be used in downstream blocks.
Example Output Format:
outputs = {
"tlds": [".com", ".net", ".org"],
"count": 3
}
return outputs
Function Registration Metadata:
When defining a custom function, you provide:
Title: Shown in the playbook interface.
Category: Helps organize functions (e.g., “Utilities” or “Parsing”).
Output schema: Defines what downstream blocks can access.
To ensure playbooks are resilient, custom Python code should gracefully handle errors and exceptions.
Pattern for Exception Handling:
try:
response = requests.get(url)
response.raise_for_status()
phantom.debug("Success: {}".format(response.json()))
except Exception as e:
phantom.error("Request failed: {}".format(str(e)))
Key Practices:
Always use try/except blocks when calling external APIs or handling untrusted data.
Use phantom.error() for logging failures to make debugging easier.
Avoid unhandled exceptions, as they can break playbook execution.
In Custom Apps:
Each action should catch exceptions and return:
status: "success" or "failed"
message: Diagnostic information
Custom code can be enhanced by dynamically pulling context-specific data using SOAR’s internal storage mechanisms.
Accessing a Custom List:
status, values = phantom.get_list("HighRiskCountries")
if status:
country_list = [entry[0] for entry in values]
Working with Saved Variables:
You can access saved values from the container or artifacts:
source_ip = container.get("source_data_identifier", "")
username = artifact.get("cef", {}).get("destinationUserName", "")
Or use phantom.collect2() for structured access:
phantom.collect2(container=container, datapath=["artifact:*.cef.sourceAddress"])
These techniques support data-driven playbook logic.
When developing custom code, it’s essential to understand the security and execution boundaries enforced by Splunk SOAR.
Code Block Environment:
Runs in a sandboxed Python 3.x interpreter.
Cannot:
Execute shell/system commands (e.g., os.system("rm -rf /"))
Access arbitrary files outside the permitted scope
Safe for logic, loops, data parsing, and API requests.
Custom App Considerations:
Apps run under a restricted SOAR runtime with limited system-level access.
Must:
Declare required permissions in the app’s YAML file
Avoid writing to protected directories
Use secure handling of credentials and tokens
Tip: Always validate and sanitize input to avoid code injection or security vulnerabilities.
| Category | Key Concepts |
|---|---|
| Input Parameters | Define type, array support, required status |
| Output Structure | Return structured dictionaries for downstream use |
| Exception Handling | Use try/except with phantom.debug() or phantom.error() |
| Integration with Lists | Use phantom.get_list() to pull reference data |
| Saved Field Access | Use .get(), artifact paths, or collect2() |
| Secure Runtime | No OS commands in code blocks; restricted file access |
| App Permissions | Declare minimal required permissions and handle creds securely |
When should developers use custom code in Splunk SOAR playbooks?
Custom code should be used when automation logic cannot be implemented using standard playbook blocks or existing app actions.
The visual playbook editor provides many built-in capabilities, but some workflows require advanced data processing or integration logic. Custom code allows developers to implement Python functions that perform specialized tasks such as complex data transformations or API interactions. However, excessive custom coding can make automation workflows harder to maintain, so it should be used only when necessary.
Demand Score: 67
Exam Relevance Score: 82
What is the purpose of custom function blocks in Splunk SOAR?
Custom function blocks allow developers to execute Python code within playbooks to perform specialized automation tasks.
These blocks extend the functionality of the playbook editor by allowing developers to write custom logic that processes playbook data. The function receives input parameters from the playbook, executes the Python code, and returns results that can be used in later workflow steps. This capability enables flexible automation workflows that can handle complex investigation scenarios.
Demand Score: 62
Exam Relevance Score: 79
Why should developers avoid unnecessary use of the global block in playbooks?
The global block executes at playbook initialization and can introduce complexity or performance issues if misused.
Code placed in the global block runs when the playbook starts and affects the entire workflow. While useful for initializing variables or performing setup tasks, excessive logic in the global block can make playbook execution harder to understand and debug. Best practice is to keep initialization logic minimal and implement most automation tasks within structured playbook blocks.
Demand Score: 54
Exam Relevance Score: 74