Skip to contents

Recursively inspects an R expression and identifies any calls to functions listed in a forbidden list. This is useful for validating code generated by large language models (LLMs) or user input before evaluating it.

Usage

find_dangerous_calls(
  expr,
  additional_forbidden = NULL,
  block_namespace_access = TRUE
)

Arguments

expr

An R expression or language object, typically returned by base::parse().

additional_forbidden

A character vector of function names to flag as disallowed. These are combined with the vector of function names from default_dangerous_calls()

block_namespace_access

A logical indicating whether to block namespace access operators (:: and :::) in the expression.

Value

A character vector of disallowed function names that were found in the expression. If none were found, returns character(0).

Details

This function traverses the expression tree recursively and checks whether any of the function calls match names in the forbidden list. It does not evaluate the expression, and it does not inspect calls constructed dynamically (e.g., via get() or match.fun()). Only syntactic references to function names are detected.

This function is useful in contexts where LLMs or other tools generate R code dynamically, and you want to enforce a safety layer before evaluation.

Examples

# Basic example with raw code
find_dangerous_calls(parse(text = "system('ls')"))
#> [1] "system"

# Multiple disallowed calls
expr <- parse(text = "unlink('file'); system2('echo', 'hi')")
find_dangerous_calls(expr)
#> [1] "unlink"  "system2"

# Using base:: syntax
find_dangerous_calls(parse(text = "base::system2('echo', 'hi')" ))
#> [1] "system2" "::"     

# Using namespace access with `::` or `:::`
find_dangerous_calls(parse(text = 'purr::map(1:3, ~ base::system("echo hi"))'))
#> [1] "::"     "system"

# Safe code
find_dangerous_calls(parse(text = "mean(c(1, 2, 3))"))
#> character(0)