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/1for 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:
to_view_mode/2- :detail, :aggregate, :graph, :timeseries, :chart, :table, :mapto_theme/2- :light, :dark, :high_contrast, :system, :autoto_sort_direction/2- :asc, :descto_form_mode/2- :collapsed, :inline, :modal, :expandedto_widget_type/2- :chart, :table, :metric, :filter, :summary, :kpi, :gaugeto_aggregate_function/2- :count, :sum, :avg, :min, :max, etc.to_list_name/2- :group_by, :aggregate, :selected, :order_by, etc.
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
atomize_keys(map, allowed_keys)
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"}
to_aggregate_function(value, default \\ :count)
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
to_atom_if_allowed(value, allowed, default)
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
to_existing(value)
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
to_existing!(value)
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"
to_form_mode(value, default \\ :collapsed)
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
to_list_name(value, default \\ :selected)
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
to_sort_direction(value, default \\ :asc)
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
to_theme(value, default \\ :light)
Safely convert a string to a theme atom.
examples
Examples
iex> SafeAtom.to_theme("dark")
:dark
iex> SafeAtom.to_theme("hacker_theme")
:light
to_theme_property(value)
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
to_view_mode(value, default \\ :detail)
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
to_widget_type(value, default \\ :table)
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
valid_theme_properties()
@spec valid_theme_properties() :: [atom()]
Returns the list of valid theme property atoms.
Useful for validating theme imports.
valid_view_modes()
@spec valid_view_modes() :: [atom()]
Returns the list of valid view mode atoms.
valid_widget_types()
@spec valid_widget_types() :: [atom()]
Returns the list of valid widget type atoms.