---
title: Variables and Actions
description: >-
  Use SECL variables and Agent rule actions to enrich events, respond to
  threats, and build stateful detection logic.
breadcrumbs: >-
  Docs > Datadog Security > Workload Protection > Detect and Monitor > Agent
  Rules > Variables and Actions
---

> For the complete documentation index, see [llms.txt](https://docs.datadoghq.com/llms.txt).

# Variables and Actions

Rule actions extend Workload Protection (Runtime Security) rules beyond detection. When a rule matches an event, the Agent can execute one or more actions to enrich the event, respond to a threat, or drive multi-step detection logic.

Actions are defined in Agent policy files (`.policy`) under the `actions` field of a rule.

{% alert level="info" %}
All actions can be configured in Agent policy files (YAML) on the Agent but `log`, `coredump`, and `network_filter` cannot be setup from the UI when creating a rule. When you create an Agent rule in Datadog, you can configure `hash`, `kill` ([automated response](https://docs.datadoghq.com/security/workload_protection/respond_and_report.md#automated-response)), and `set` actions. From a security signal, you can manually apply `kill` or `network_filter` to a targeted threat with [manual response](https://docs.datadoghq.com/security/workload_protection/respond_and_report.md#response).
{% /alert %}

| Action           | Purpose                                               | Platform       | Requires enforcement |
| ---------------- | ----------------------------------------------------- | -------------- | -------------------- |
| `set`            | Store state in a variable for use by other rules      | Linux, Windows | No                   |
| `kill`           | Terminate a process                                   | Linux, Windows | Yes                  |
| `hash`           | Compute hashes of a file                              | Linux          | No                   |
| `log`            | Write a message to the Agent log                      | Linux, Windows | No                   |
| `coredump`       | Capture forensic state (process, mount, dentry)       | Linux          | No                   |
| `network_filter` | Monitor or drop network traffic matching a BPF filter | Linux          | Yes                  |

## Syntax{% #syntax %}

Each rule can define multiple actions as a YAML list. Each list item must contain exactly one action type.

```yaml
rules:
  - id: my_rule
    expression: exec.file.name == "suspicious_binary"
    actions:
      - set:
          name: flagged_process
          value: true
          ttl: 5m
      - kill:
          signal: SIGKILL
          scope: process
```

### Action filters{% #action-filters %}

Every action supports an optional `filter` field: a SECL expression evaluated at action time. The action runs only when both the rule expression and the action filter match.

| Field    | Required | Default                                | Description                               |
| -------- | -------- | -------------------------------------- | ----------------------------------------- |
| `filter` | No       | None (action runs on every rule match) | SECL expression evaluated at action time. |

```yaml
rules:
  - id: kill_container_process
    expression: exec.file.name == "malware"
    actions:
      - filter: process.container.id != ""
        kill:
          signal: SIGTERM
          scope: container
```

## `set`: store variables{% #set-store-variables %}

Use `set` to store state that persists across rules within the same policy. After it is defined, a variable can be referenced from any other rule in that policy.

### When to use it{% #when-to-use-it %}

Variables are one of the most powerful capabilities in Agent rule authoring. They are essential for building stateful, multi-step detections that go beyond what a single SECL expression can express on its own.

- Chain rules within a policy by recording context in one rule and matching a follow-up rule that references that variable.
- Build rolling lists of process names, paths, or DNS activity.

### Parameters{% #parameters %}

| Field           | Required                                 | Default                         | Description                                                                                      |
| --------------- | ---------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------ |
| `name`          | Yes                                      | —                               | Variable name. Referenced in expressions as `${name}` or `${scope.name}`.                        |
| `value`         | One of `value`, `field`, or `expression` | —                               | Static value (string, integer, Boolean, or array).                                               |
| `field`         | One of `value`, `field`, or `expression` | —                               | Copy a value from the triggering event (for example, `process.file.name`).                       |
| `expression`    | One of `value`, `field`, or `expression` | —                               | SECL expression whose result is stored. Requires `default_value` if type cannot be inferred.     |
| `default_value` | No                                       | —                               | Default when using `expression`. Must match the type of `value`.                                 |
| `scope`         | No                                       | Global (no scope prefix)        | `process`, `container`, or `cgroup`. Prefixes the variable name (for example, `process.my_var`). |
| `scope_field`   | No                                       | Triggering process PID          | Custom scope key (`process` scope only).                                                         |
| `append`        | No                                       | `false`                         | Append to a list variable instead of overwriting.                                                |
| `size`          | No                                       | `100` (when `append` is `true`) | Maximum list length when `append` is `true`.                                                     |
| `ttl`           | No                                       | No expiration                   | Time-to-live (for example, `10s`, `5m`). Variable expires after this duration.                   |
| `inherited`     | No                                       | `false`                         | Variable is inherited by child processes (`process` scope only).                                 |
| `private`       | No                                       | `false`                         | Variable is not exposed in security events.                                                      |

### Examples{% #examples %}

Set a Boolean flag:

```yaml
rules:
  - id: flag_suspicious_exec
    expression: exec.file.path in ["/tmp/evil"]
    actions:
      - set:
          name: suspicious
          value: true
          ttl: 10m
  - id: detect_follow_up
    expression: open.file.path == "/etc/shadow" && ${suspicious}
```

Collect DNS queries into a rolling list:

```yaml
rules:
  - id: collect_dns_queries
    expression: dns.question.name != ""
    actions:
      - set:
          name: queried_domains
          field: dns.question.name
          append: true
          size: 10
          ttl: 10s
          scope: process
```

Create a correlation rule:

Use `private` to keep internal state out of security events, and `scope_field` to bind a variable to a process other than the one that triggered the event (for example, the target of a `cgroup_write` event):

```yaml
rules:
  - id: init_correlation_key
    expression: cgroup_write.file.path != "" && ${process.correlation_key} == ""
    actions:
      - set:
          name: correlation_key
          default_value: ""
          expression: '"attack_${builtins.uuid4}"'
          scope: process
          scope_field: cgroup_write.pid
          inherited: true
          private: true
  - id: detect_correlated_file_access
    expression: open.file.path == "/etc/shadow" && ${process.correlation_key} != ""
```

Compute a value from an expression: Use `expression` with `default_value` to define the variable type and store a computed result.

```yaml
rules:
  - id: record_exec_context
    expression: exec.file.path in ["/tmp/evil"]
    actions:
      - set:
          name: exec_context
          default_value: ""
          expression: '"cmd_${process.pid}_${exec.file.name}"'
          scope: process
          ttl: 5m
```

## `kill`: terminate a process{% #kill-terminate-a-process %}

Use `kill` to actively stop malicious activity. The Agent sends a POSIX signal to the target process, container, or cgroup.

### Configure in Datadog{% #configure-in-datadog %}

In addition to defining `kill` actions in Agent policy files, you can configure process termination in Datadog:

- **Automatic:** Add `kill` actions to Agent rules in a policy, as described in this section, or use [automated response](https://docs.datadoghq.com/security/workload_protection/respond_and_report.md#automated-response).
- **Manual:** From a security signal, use [Kill containers or processes](https://docs.datadoghq.com/security/workload_protection/investigate_and_triage/security_signals/actions.md#kill-containers-or-processes) under Respond in the signal side panel.

Both approaches require [Agent enforcement](https://docs.datadoghq.com/security/workload_protection/respond_and_report.md#configure-agent-enforcement), which is enabled by default. See [Respond to Threats](https://docs.datadoghq.com/security/workload_protection/respond_and_report.md) for an overview of enforcement and response actions.

### When to use it{% #when-to-use-it-1 %}

- Block cryptomining, reverse shells, or known malware at runtime.
- Gracefully stop a process (`SIGTERM`) or force-kill it (`SIGKILL`).

### Requirements{% #requirements %}

- Enforcement must be enabled in the Agent configuration (`runtime_security_config.enforcement.enabled`). See [Advanced configuration](https://docs.datadoghq.com/security/workload_protection/setup/advanced_configuration.md).
- Kill actions are rejected at policy load time if enforcement is globally disabled.
- Supported signals include `SIGKILL`, `SIGTERM`, `SIGHUP`, `SIGINT`, and other standard POSIX signal names.

### Parameters{% #parameters-1 %}

| Field                         | Required | Default   | Description                                                                         |
| ----------------------------- | -------- | --------- | ----------------------------------------------------------------------------------- |
| `signal`                      | Yes      | —         | Signal name (for example, `SIGKILL`, `SIGTERM`).                                    |
| `scope`                       | No       | `process` | `process`, `container`, or `cgroup`. Determines which processes receive the signal. |
| `disable_container_disarmer`  | No       | `false`   | Disable the automatic container disarmer safeguard.                                 |
| `disable_executable_disarmer` | No       | `false`   | Disable the automatic executable disarmer safeguard.                                |

### Safeguards{% #safeguards %}

The Agent includes disarmers to prevent runaway kill loops during automated response. If too many kill actions fire against the same container or executable within a configured period, subsequent kills for that target are suppressed until the period expires.

Certain binaries can also be excluded from enforcement through `runtime_security_config.enforcement.exclude_binaries`.

### Example{% #example %}

```yaml
rules:
  - id: block_ping_process
    expression: >-
      exec.file.name == "ping"
    actions:
      - kill:
          signal: SIGKILL
          scope: process
```

#### Kill action report{% #kill-action-report %}

When a `kill` action runs, the Agent attaches an action report to the triggering Agent event in `agent.rule_actions`. This is not a separate custom event—the report is serialized with the security event that matched the rule. For `SIGKILL`, the Agent may delay sending the event until the target process exits so timing fields are accurate.

| Field           | Description                                                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `type`          | Always `kill`                                                                                                                        |
| `signal`        | POSIX signal sent (for example, `SIGKILL`, `SIGTERM`)                                                                                |
| `scope`         | `process`, `container`, or `cgroup`                                                                                                  |
| `status`        | Execution outcome: `performed`, `partially_performed`, `error`, `kill_queued`, `kill_aborted`, `rule_disarmed`, or `rule_dismantled` |
| `disarmer_type` | Safeguard that blocked or altered the kill: `container` or `executable` (when applicable)                                            |
| `created_at`    | Time the target process was created                                                                                                  |
| `detected_at`   | Time the rule matched                                                                                                                |
| `killed_at`     | Time the signal was sent (when applicable)                                                                                           |
| `exited_at`     | Time the target process exited (when applicable)                                                                                     |
| `ttr`           | Elapsed time from process creation to exit                                                                                           |

To count how many times a `kill` action ran after a rule match, use the `datadog.runtime_security_config.rules.action_performed` metric with tags `rule_id:<rule_id>` and `action_name:kill`.

## `network_filter`: monitor or block network traffic{% #network_filter-monitor-or-block-network-traffic %}

Use `network_filter` to drop packets matching a BPF filter expression for the offending process or cgroup. This is network isolation at the host level.

### Configure in Datadog{% #configure-in-datadog-1 %}

In addition to defining `network_filter` actions in Agent policy files, you can isolate a compromised workload in Datadog:

- **Automatic:** Add `network_filter` actions to Agent rules in a policy, as described in this section. When a rule matches, the Agent drops matching traffic automatically.
- **Manual:** From a security signal, use [Network isolation](https://docs.datadoghq.com/security/workload_protection/investigate_and_triage/security_signals/actions.md#network-isolation) under Respond in the signal side panel.

### When to use it{% #when-to-use-it-2 %}

- Cut off C2 communication after detecting a malicious process.
- Block DNS or specific port traffic from a compromised container.

### Requirements{% #requirements-1 %}

- Enforcement must be enabled.
- The `raw_packet` event type must be enabled in the Agent configuration.
- Linux only (eBPF-based packet filtering).

### Parameters{% #parameters-2 %}

| Field    | Required | Default   | Description                                                    |
| -------- | -------- | --------- | -------------------------------------------------------------- |
| `filter` | Yes      | —         | BPF filter expression (for example, `port 53`, `tcp port 80`). |
| `policy` | No       | `allow`   | `drop` or `allow`. Only `drop` enforces packet dropping.       |
| `scope`  | No       | `process` | `process` or `cgroup`.                                         |

### Example{% #example-1 %}

```yaml
rules:
  - id: block_malicious_container_network
    expression: exec.container.id == "046f6a38c8b404a78fb9be56672d554ed5a326f4c568ffb137e16cf3e7e6be43"
    actions:
      - network_filter:
          filter: "dst net 10.0.0.0/8 or dst net 172.16.0.0/12 or dst net 192.168.0.0/16 or dst net 169.254.0.0/16 or dst net 127.0.0.0/8"
          policy: drop
          scope: cgroup
```

### Raw packet action and metrics{% #raw-packet-action-and-metrics %}

#### Raw packet action event{% #raw-packet-action-event %}

When the kernel drops a packet that matches an active filter, the Agent can emit a `rawpacket_action` custom event (`@agent.rule_id:rawpacket_action`). These events are rate-limited under high drop volume, because the Agent cannot send one event for every dropped packet. The event payload includes:

| Field            | Description                                                          |
| ---------------- | -------------------------------------------------------------------- |
| `packet.dropped` | `true` for dropped packets                                           |
| `packet.layers`  | Decoded network layers (Ethernet, IP, TCP/UDP, and so on)            |
| `packet.tls`     | TLS context when available                                           |
| `network`        | Network context for the dropped packet (device, source, destination) |

#### Metrics{% #metrics %}

To track drop counts reliably, use the `datadog.runtime_security_config.network.raw_packet.dropped` metric.

## `hash`: compute file hashes{% #hash-compute-file-hashes %}

Use `hash` to enrich an event with cryptographic hashes of a file referenced in the triggering event. This is useful for threat intelligence matching and forensic analysis.

### When to use it{% #when-to-use-it-3 %}

- Hash a binary at exec time before it is deleted or modified.
- Hash a file opened for write to correlate with known malware signatures.

### Parameters{% #parameters-3 %}

| Field           | Required | Default                                                                      | Description                                                                                       |
| --------------- | -------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `field`         | No       | `exec.file` for `exec` rules; `open.file` for `open` rules                   | File event field to hash (for example, `exec.file`, `open.file`). Required for other event types. |
| `max_file_size` | No       | `5242880` (5 MB), from `runtime_security_config.hash_resolver.max_file_size` | Maximum file size (bytes) to hash. Larger files are skipped.                                      |

### Supported algorithms{% #supported-algorithms %}

Hashes are computed by the Agent hash resolver and may include `MD5`, `SHA1`, `SHA256`, and `SSDEEP`, depending on Agent configuration. Results appear in the `*.hashes` field of the file event (for example, `exec.file.hashes`). To change the algorithms used, update `runtime_security_config.hash_resolver.hash_algorithms` in `system-probe.yaml` or set `DD_RUNTIME_SECURITY_CONFIG_HASH_RESOLVER_HASH_ALGORITHMS`. See [Workload Protection Agent configuration](https://docs.datadoghq.com/security/workload_protection/setup/advanced_configuration.md) for all hash resolver parameters.

### Example{% #example-2 %}

```yaml
rules:
  - id: hash_dropped_binary
    expression: exec.file.path startswith "/tmp/" && exec.file.name not in ["systemd"]
    actions:
      - hash:
          field: exec.file
          max_file_size: 10485760  # 10 MB
```

## `log`: write to Agent logs{% #log-write-to-agent-logs %}

Use `log` to emit a structured message to the Runtime Security Agent log when a rule fires. This is helpful for debugging custom rules or auditing rule triggers without generating a full security signal.

### When to use it{% #when-to-use-it-4 %}

- Debug rule logic during development.

### Parameters{% #parameters-4 %}

| Field     | Required | Default                    | Description                                        |
| --------- | -------- | -------------------------- | -------------------------------------------------- |
| `level`   | Yes      | —                          | Log level: `debug`, `info`, `warning`, or `error`. |
| `message` | No       | `Rule <rule_id> triggered` | Custom message.                                    |

### Example{% #example-3 %}

```yaml
rules:
  - id: log_sensitive_file_access
    expression: open.file.path startswith "/etc/"
    actions:
      - log:
          level: warning
          message: "Suspicious file access detected on sensitive path"
```

## `coredump`: capture forensic state{% #coredump-capture-forensic-state %}

Use `coredump` to snapshot internal Agent state at the time of a rule match. The dump is gzip-compressed (unless disabled) and attached to the security event.

### When to use it{% #when-to-use-it-5 %}

- Mostly used for debug purposes.
- Capture internal context caches such as process tree, mount table, or dentry cache state alongside the triggering event.

### Platform{% #platform %}

Linux only.

### Parameters{% #parameters-5 %}

At least one of `process`, `mount`, or `dentry` must be set to `true`.

| Field            | Required     | Default                            | Description                                   |
| ---------------- | ------------ | ---------------------------------- | --------------------------------------------- |
| `process`        | At least one | `false`                            | Include the process resolver snapshot.        |
| `mount`          | At least one | `false`                            | Include the mount resolver snapshot.          |
| `dentry`         | At least one | `false`                            | Include the dentry resolver snapshot.         |
| `no_compression` | No           | `false` (gzip compression enabled) | Disable gzip compression of the dump payload. |

### Example{% #example-4 %}

```yaml
rules:
  - id: capture_forensic_state
    expression: exec.file.path startswith "/tmp/" && process.container.id != ""
    actions:
      - coredump:
          process: true
          mount: true
          dentry: true
          no_compression: false
```

## Combining actions{% #combining-actions %}

A single rule can chain multiple actions. They execute in list order when the rule matches:

```yaml
rules:
  - id: detect_and_respond
    expression: exec.file.path == "/tmp/payload"
    actions:
      - set:
          name: payload_seen
          value: true
      - hash:
          field: exec.file
      - log:
          level: info
          message: "Payload executed, hashing and killing"
      - kill:
          signal: SIGKILL
          scope: process
```

Typical patterns:

| Pattern                 | Actions                                       |
| ----------------------- | --------------------------------------------- |
| Detect → enrich → alert | `hash` only (signal sent automatically)       |
| Detect → respond        | `kill` or `network_filter`                    |
| Multi-step detection    | `set` in rule A, reference `${var}` in rule B |
| Debug custom rules      | `log`                                         |

## Platform summary{% #platform-summary %}

| Action           | Linux | Windows |
| ---------------- | ----- | ------- |
| `set`            | ✅     | ✅       |
| `kill`           | ✅     | ✅       |
| `hash`           | ✅     | ❌       |
| `log`            | ✅     | ✅       |
| `coredump`       | ✅     | ❌       |
| `network_filter` | ✅     | ❌       |

## Validation rules{% #validation-rules %}

The Agent validates actions at policy load time:

- **One action type per list item**: `set` and `kill` cannot appear in the same action block.
- **Required fields**: for example, `kill.signal`, `log.level`, `network_filter.filter`.
- **Enforcement gate**: `kill` and `network_filter` require enforcement to be enabled.
- **Event type compatibility**: `network_filter` requires the `raw_packet` event type; `hash.field` must be compatible with the rule's event type.
