Inspecting Elixir Dependencies at Runtime for Security

Michael Lubas, 2023-07-05

A common pattern in vulnerability response is that a library has a bad security problem, and you want to check what version is running in production. The syntax of most dependency specification files (including Elixir’s mix.exs) means the exact version running cannot be determined from the file alone. Consider a library where 2.0.3 is not vulnerable, but 2.0.4 is. The project’s mix file has "~> 2.0.0", meaning ">= 2.0.0 and < 2.1.0". The reply to “Are we vulnerable right now?” is an uncomfortable “Maybe, there’s not enough information here”.

Even worse, the security team may decide to search through source code repos (Github, Gitlab, etc) for the relevant library. No matches are found but the vulnerability is present, because it is a sub-dependency of a dependency. While the mix.lock for an Elixir project may be in Github, there is no guarantee that file matches what is running in production.

To find out exactly what version is running, ssh into the relevant server:

% fly ssh console

Then connect to the running Elixir application. If you are using releases:

./bin/release_name remote

See this ElixirForum thread if you are not using releases. Now run the following to list all loaded applications:

iex> Application.loaded_applications() |> Enum.sort_by(&(elem(&1, 0))) |> length()

[
  {:asn1, 'The Erlang ASN1 compiler version 5.0.19', '5.0.19'},
  {:bcrypt_elixir, 'Bcrypt password hashing algorithm for Elixir', '3.0.1'},
...
  {:yamerl, 'YAML 1.2 and JSON parser in pure Erlang', '0.10.0'},
  {:yaml_elixir,
   'YAML parser for Elixir based on native Erlang implementation.\n', '2.9.0'}
]
78

This line of code does the following:

1. List all loaded applications.

2. Sort by the name of each application.

3. Return the length of the list, which is the total number of applications.

The process described here is useful in emergency situations, however the weaknesses are obvious:

1. A vulnerability is announced on June 2 and the security team decides to check on June 9 if the company is vulnerable. There is no record of exactly what was running in production. The company is not able to construct an accurate timeline of when they were exposed.

2. There is no automatic recording at runtime. Reports can be created showing the output of these commands, but the manual process of putting the data together is tedious, error prone, and should be automated.

Introducing App Audit

App Audit is a new feature in Paraxial.io, which solves this problem by automatically recording an audit for the Elixir application at runtime. To use App Audit, simply install Paraxial.io in your project:

{:paraxial, "~> 2.5"} - https://hex.pm/packages/paraxial

Configure the agent:

config :paraxial,
  paraxial_api_key: System.get_env("PARAXIAL_API_KEY"),  
  paraxial_url: "https://app.paraxial.io"

Then start your application:

mix phx.server

The audit results will be uploaded:

To view the results of past audits, click the “History” tab.

This page displays each audit for the site. App Audit is included with Paraxial.io Application Secure. Reach out today to schedule a demo.


Paraxial.io stops data breaches by helping developers ship secure applications. Get a demo or start for free.

Subscribe to stay up to date on new posts.