← All docs

Rule recipes

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

These rules are ready to drop into a policy file. Each covers a common scenario. Adjust the strings and messages to fit your setup.

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

Block access to sensitive paths

Deny any Bash command that touches ~/.ssh:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "/.ssh/")
  msg := "Blocked: command targets ~/.ssh/"
}

Deny access to .env files:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, ".env")
  msg := "Blocked: command references a .env file"
}

Deny access to ~/.aws credentials:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "/.aws/")
  msg := "Blocked: command targets ~/.aws/ credentials"
}

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

deny[msg] {
  input.tool_name == "Read"
  contains(input.tool_input.file_path, "/.ssh/")
  msg := "Blocked: read from ~/.ssh/ is not allowed"
}

deny[msg] {
  input.tool_name == "Write"
  endswith(input.tool_input.file_path, ".pem")
  msg := "Blocked: write to a .pem file is not allowed"
}

Block destructive commands

Deny rm -rf invocations:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "rm -rf")
  msg := "Blocked: rm -rf is not allowed"
}

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

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "| sh")
  msg := "Blocked: pipe-to-shell pattern detected"
}

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "| bash")
  msg := "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:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "curl")
  not contains(input.tool_input.command, "api.yourcompany.com")
  msg := "Blocked: curl to an unexpected host"
}

Apply the same pattern for wget:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "wget")
  not contains(input.tool_input.command, "api.yourcompany.com")
  msg := "Blocked: wget to an unexpected host"
}

Block git push to protected remotes

There is no dedicated git tool. 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):

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "origin")
  msg := "Blocked: git push to origin requires manual approval"
}

Deny force-push specifically:

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "--force")
  msg := "Blocked: force push is not allowed"
}

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "-f ")
  msg := "Blocked: force push is not allowed"
}

Combining conditions

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

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "curl")
  contains(input.tool_input.command, "/.ssh/")
  msg := "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.