Restrictions & Best Practices

Security restrictions and best practices for writing effective policies

For security reasons, policies run in a restricted environment. This page documents what is not allowed and provides best practices for writing effective policies.

Policy Limits

Policies are limited to 2,048 characters in length. This encourages concise, focused rules and ensures fast evaluation times.


Platform-Level Restrictions

The following RPC methods are blocked at the platform level and cannot be enabled by any policy:

CategoryMethods
Debug & Tracedebug_*, trace_*
Legacy Filterseth_newFilter, eth_newBlockFilter, eth_newPendingTransactionFilter, eth_getFilterChanges, eth_getFilterLogs, eth_uninstallFilter

These restrictions apply to all requests regardless of organization or endpoint policies.


eth_getLogs Limitations

The eth_getLogs method is restricted to single block queries only. You must specify either:

  • block_hash: Query logs from a specific block hash
  • block_number: Query logs from a specific block number (hex format like 0x100 or tags like latest)

Block range queries using fromBlock and toBlock are not supported. This restriction applies to both RPC and MCP requests.


Blocked Keywords

The following patterns are not allowed in policies:

PatternReason
import ...Cannot import external modules
package ...Cannot declare packages
default ...Cannot override default values
data.*Cannot reference external data

Policies attempting to use these patterns will fail validation.


Disabled Built-ins

These built-in categories are disabled and will be rejected:

PatternError Message
http.send"http.send is disabled"
crypto.*"Crypto functions are disabled"
io.jwt.*"JWT functions are disabled"
yaml.*"YAML functions are disabled"
uuid.*"UUID functions are disabled"
glob.*"Glob functions are disabled"
semver.*"Semver functions are disabled"
json.schema*"JSON schema functions are disabled"
graphql.*"GraphQL functions are disabled"
net.cidr*"Net CIDR functions are disabled"
opa.runtime*"OPA runtime functions are disabled"
rego.metadata*"Rego metadata functions are disabled"

Policies using disabled builtins will fail validation with a clear error message indicating which function is not allowed.


Validation Errors

When a policy fails validation, you'll receive errors like:

ErrorCause
"Import statements are not allowed"Policy contains import
"Package declarations are not allowed"Policy contains package
"Default statements are not allowed"Policy contains default
"Data references are not allowed"Policy contains data.

When compilation fails due to invalid Rego syntax, you'll receive the line number and error message from the compiler.


Best Practices

Lowercase Addresses

Always use lower() for case-insensitive address matching:

# Good: Normalized comparison
deny if {
    lower(input.to_address) == "0xdead..."
}
 
# Bad: May miss matches due to case differences
deny if {
    input.to_address == "0xDead..."
}

Handle Nullable Fields

Some input fields can be null. Handle this gracefully:

# Good: Check for null before comparison
deny if {
    input.usd_value != null
    input.usd_value > 10000
}
 
# Alternative: Use type checking
deny if {
    is_number(input.usd_value)
    input.usd_value > 10000
}

Test Thoroughly

Before deploying policies to production:

  1. Test with various input combinations
  2. Verify both allow and deny cases
  3. Check edge cases (null values, empty arrays)
  4. Validate against realistic transaction data

Document Your Rules

Use comments to explain complex logic:

# Block high-value transactions during off-hours
# Business hours are 9 AM - 5 PM UTC, Monday-Friday
deny if {
    [hour, _, _] := time.clock(time.now_ns())
    hour < 9
    input.usd_value > 1000
}

Use Meaningful Variable Names

When using local variables, choose descriptive names:

# Good: Clear variable names
deny if {
    high_risk_threshold := 10000
    input.usd_value > high_risk_threshold
}
 
# Avoid: Cryptic names
deny if {
    x := 10000
    input.usd_value > x
}
Restrictions & Best Practices | 256 Blocks