SelectoComponents.SafeAtom (selecto_components v0.4.5)

Safe atom conversion functions to prevent atom table exhaustion attacks.

security

Security

Elixir atoms are never garbage collected. If user input is directly converted to atoms via String.to_atom/1, an attacker can exhaust the atom table (default limit ~1 million atoms) causing a Denial of Service.

This module provides safe alternatives that:

  • Validate input against whitelists before conversion
  • Use String.to_existing_atom/1 for schema-derived values
  • Return safe defaults for invalid input

usage

Usage

# Instead of:
view = String.to_atom(params["view_mode"])

# Use:
view = SafeAtom.to_view_mode(params["view_mode"])

functions

Functions

Each function validates against a specific whitelist:

For schema-derived values (field names, table names), use to_existing/1 which wraps String.to_existing_atom/1 with proper error handling.

Link to this section Summary

Functions

Safely atomize map keys, only keeping keys that are in the allowed list.

Safely convert a string to an aggregate function atom.

Generic function to convert a string to an atom if it's in the allowed list.

Convert a string to an existing atom, or return nil if it doesn't exist.

Convert a string to an existing atom, raising if it doesn't exist.

Safely convert a string to a form mode atom.

Safely convert a string to a list name atom.

Safely convert a string to a sort direction atom.

Safely convert a string to a theme atom.

Safely convert a string to a theme property atom.

Safely convert a string to a view mode atom.

Safely convert a string to a widget type atom.

Returns the list of valid theme property atoms.

Returns the list of valid view mode atoms.

Returns the list of valid widget type atoms.

Link to this section Functions

Link to this function

atomize_keys(map, allowed_keys)

@spec atomize_keys(map(), [atom()]) :: map()

Safely atomize map keys, only keeping keys that are in the allowed list.

Keys not in the allowed list are dropped from the result.

examples

Examples

iex> SafeAtom.atomize_keys(%{"primary_500" => "#fff", "evil" => "bad"}, @valid_theme_properties)
%{primary_500: "#fff"}
Link to this function

to_aggregate_function(value, default \\ :count)

@spec to_aggregate_function(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to an aggregate function atom.

examples

Examples

iex> SafeAtom.to_aggregate_function("sum")
:sum

iex> SafeAtom.to_aggregate_function("DROP")
:count
Link to this function

to_atom_if_allowed(value, allowed, default)

@spec to_atom_if_allowed(String.t() | nil, [atom()], atom() | nil) :: atom() | nil

Generic function to convert a string to an atom if it's in the allowed list.

Returns the default if the string is not in the allowed list.

examples

Examples

iex> SafeAtom.to_atom_if_allowed("foo", [:foo, :bar], :default)
:foo

iex> SafeAtom.to_atom_if_allowed("baz", [:foo, :bar], :default)
:default
Link to this function

to_existing(value)

@spec to_existing(String.t() | atom() | nil) :: atom() | nil

Convert a string to an existing atom, or return nil if it doesn't exist.

This is safe because it only converts to atoms that already exist in the atom table (e.g., from compiled schema definitions).

examples

Examples

iex> SafeAtom.to_existing("id")  # Assuming :id exists
:id

iex> SafeAtom.to_existing("nonexistent_atom_xyz123")
nil
Link to this function

to_existing!(value)

@spec to_existing!(String.t() | atom()) :: atom()

Convert a string to an existing atom, raising if it doesn't exist.

Use this when you expect the atom to exist (e.g., schema field names) and want to fail fast if it doesn't.

examples

Examples

iex> SafeAtom.to_existing!("id")  # Assuming :id exists
:id

iex> SafeAtom.to_existing!("nonexistent")
** (ArgumentError) not an existing atom: "nonexistent"
Link to this function

to_form_mode(value, default \\ :collapsed)

@spec to_form_mode(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to a form mode atom.

examples

Examples

iex> SafeAtom.to_form_mode("modal")
:modal

iex> SafeAtom.to_form_mode("evil")
:collapsed
Link to this function

to_list_name(value, default \\ :selected)

@spec to_list_name(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to a list name atom.

examples

Examples

iex> SafeAtom.to_list_name("group_by")
:group_by

iex> SafeAtom.to_list_name("hacked")
:selected
Link to this function

to_sort_direction(value, default \\ :asc)

@spec to_sort_direction(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to a sort direction atom.

examples

Examples

iex> SafeAtom.to_sort_direction("asc")
:asc

iex> SafeAtom.to_sort_direction("DROP TABLE")
:asc
Link to this function

to_theme(value, default \\ :light)

@spec to_theme(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to a theme atom.

examples

Examples

iex> SafeAtom.to_theme("dark")
:dark

iex> SafeAtom.to_theme("hacker_theme")
:light
Link to this function

to_theme_property(value)

@spec to_theme_property(String.t() | nil) :: atom() | nil

Safely convert a string to a theme property atom.

Used when atomizing keys from imported theme JSON.

examples

Examples

iex> SafeAtom.to_theme_property("primary_500")
:primary_500

iex> SafeAtom.to_theme_property("malicious_key")
nil
Link to this function

to_view_mode(value, default \\ :detail)

@spec to_view_mode(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to a view mode atom.

Returns the atom if valid, otherwise returns the default.

examples

Examples

iex> SafeAtom.to_view_mode("detail")
:detail

iex> SafeAtom.to_view_mode("malicious_input")
:detail

iex> SafeAtom.to_view_mode("aggregate", :graph)
:aggregate

iex> SafeAtom.to_view_mode(nil)
:detail
Link to this function

to_widget_type(value, default \\ :table)

@spec to_widget_type(String.t() | atom() | nil, atom()) :: atom()

Safely convert a string to a widget type atom.

examples

Examples

iex> SafeAtom.to_widget_type("chart")
:chart

iex> SafeAtom.to_widget_type("malware")
:table
Link to this function

valid_theme_properties()

@spec valid_theme_properties() :: [atom()]

Returns the list of valid theme property atoms.

Useful for validating theme imports.

Link to this function

valid_view_modes()

@spec valid_view_modes() :: [atom()]

Returns the list of valid view mode atoms.

Link to this function

valid_widget_types()

@spec valid_widget_types() :: [atom()]

Returns the list of valid widget type atoms.