Skip to content

TheFirstAvenger/safe_code

Repository files navigation

SafeCode

SafeCode is currently a very early stage project to answer the question "Is this code safe to load and run in an elixir application?". The immediate driving force is the potential need to answer this question in the Beacon LiveView CMS. It also has potential to be used in other projects that load code dynamically such as LiveBook.

Load code into a running application?

Yes! One of Elixirs many strengths is the ability to load modules on the fly via the Code.compile_string function. However, with great power comes great responsibility. As noted in the function docs: "Warning: string can be any Elixir code and code can be executed with the same privileges as the Erlang VM: this means that such code could compromise the machine (for example by executing system commands). Don't use compile_string/2 with untrusted input (such as strings coming from the network)."

What is safe?

One of the questions to answer as this project develops is "what is safe". While it is obvious that System.cmd("rm", ["-rf", "/"]) is not safe, and 1 + 1 is safe, what about IO.puts? Could overloading logging be an attack vector? And what about non-tail recursion or simply running code that chews up cpu cycles? What about process communication? Can that be allowed safely? At the outset we are focusing on determining what simple code is safe (e.g. Enum.map(vals, fn {x, y} -> x + y end)), but the more advanced attack vectors are front of mind.

Heex Templates

As Beacon LiveView CMS is an early potential use of SafeCode, we will out of the gate support validating both regular Elixir code and Heex templates. This will allow a user to define Beacon Components by entering the LiveComponent code via a web interface, and load that code into memory on a running system to be rendered on request.

Allow list

This project is using an allow-list approach. We are parsing the code into AST and checking if each function call in the AST is allowed. If any function validators return true for a given function, the call passes. If no function validators return true for any given function call, SafeCode raises.

Usage

The main entry points are SafeCode.Validator.validate/2 and SafeCode.Validator.validate_heex!/2. validate/2 takes straight Elixir code and tests against the Elixir FunctionValidator, and validate_heex!/2 takes Phoenix Template code and tests against both Elixir and Phoenix FunctionValidators.

Defining additional function validators

Additional function validators can be specified by passing the extra_function_validators keyword option like this (supports single validator or list of validators):

SafeCode.Validator.validate_heex!(body, extra_function_validators: MyApp.SafeCodeValidator)

These validator(s) should implement SafeCode.Validator.FunctionValidators.Behaviour. As this is an allow-list approach, your implemented functions should return true if the function is valid, false if it cannot be vouched for. SafeCode will move on to other validators until it finds one willing to vouch for the function by returning true. See the Elixir and Phoenix Function Validators in the same folder as the behaviour for examples.

Installation

Add safe_code to your list of dependencies in mix.exs:

def deps do
  [
    {:safe_code, "~> 0.2.3"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/safe_code.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages