← All docs

Rule recipes

Copy-pasteable candidate rules for common cases: sensitive paths, destructive commands, network egress, and git push guards.

These rules are ready to adapt and install via agentjail policy add. Each covers a common scenario: adjust the strings, rule_id, and reason to fit your setup.

All rules use the candidate contains r if { ... } pattern in package agentjail. Replace my_policy in each rule_id with your filename stem.

For the fields each rule references, see The input schema.

Block access to sensitive paths

Deny any Bash command that touches ~/.ssh:

package agentjail

import future.keywords.if
import future.keywords.contains

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "/.ssh/")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-ssh-access",
    "reason":  "Blocked: command targets ~/.ssh/",
  }
}

Deny access to .env files:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, ".env")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-env-access",
    "reason":  "Blocked: command references a .env file",
  }
}

Deny access to ~/.aws credentials:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "/.aws/")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-aws-access",
    "reason":  "Blocked: command targets ~/.aws/ credentials",
  }
}

You can also block file-tool access to sensitive paths:

candidate contains r if {
  input.tool_name == "Read"
  contains(input.tool_input.file_path, "/.ssh/")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-ssh-read",
    "reason":  "Blocked: read from ~/.ssh/ is not allowed",
  }
}

candidate contains r if {
  input.tool_name == "Write"
  endswith(input.tool_input.file_path, ".pem")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-pem-write",
    "reason":  "Blocked: write to a .pem file is not allowed",
  }
}

Block destructive commands

Deny rm -rf invocations:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "rm -rf")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-rm-rf",
    "reason":  "Blocked: rm -rf is not allowed",
  }
}

Deny pipe-to-shell patterns (a common exfiltration or supply-chain vector):

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "| sh")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-pipe-to-sh",
    "reason":  "Blocked: pipe-to-shell pattern detected",
  }
}

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "| bash")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-pipe-to-bash",
    "reason":  "Blocked: pipe-to-bash pattern detected",
  }
}

Block unexpected network egress

There is no dedicated network tool. curl, wget, and similar commands run through the Bash tool, so match on the command string:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "curl")
  not contains(input.tool_input.command, "api.yourcompany.com")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-unexpected-curl",
    "reason":  "Blocked: curl to an unexpected host",
  }
}

Apply the same pattern for wget:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "wget")
  not contains(input.tool_input.command, "api.yourcompany.com")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-unexpected-wget",
    "reason":  "Blocked: wget to an unexpected host",
  }
}

Block git push to protected remotes

Git commands run through the Bash tool, so match on the command string.

Deny any git push that targets origin (adjust to your protected remote name):

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "origin")
  r := {
    "action":  "ask",
    "rule_id": "custom/my_policy/confirm-git-push-origin",
    "reason":  "git push to origin requires manual approval",
  }
}

Deny force-push specifically:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "--force")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-force-push",
    "reason":  "Blocked: force push is not allowed",
  }
}

Combining conditions

Rules are conjunctions: all lines in the body must hold. You can combine conditions freely:

candidate contains r if {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "curl")
  contains(input.tool_input.command, "/.ssh/")
  r := {
    "action":  "deny",
    "rule_id": "custom/my_policy/no-ssh-exfil",
    "reason":  "Blocked: curl with SSH path looks like exfiltration",
  }
}

This fires only when both curl and /.ssh/ appear in the same command.

For testing that these rules fire correctly, see Testing policies.