Module: Glib::Params::Allowlist

Extended by:
ActiveSupport::Concern
Defined in:
app/controllers/concerns/glib/params/allowlist.rb

Defined Under Namespace

Classes: UnrecognizedValue

Instance Method Summary collapse

Instance Method Details

#glib_allowlist_symbol_param(value, allowed_symbols, default:) ⇒ Object

Resolve a stringly-typed request param (or any boundary string) to one symbol drawn from a closed allow-list (+allowed_symbols+), returning default when the value is missing, blank, or not recognised.

This is the symbol-DoS-safe replacement for params[:x].to_sym. A bare .to_sym on a raw value mints a symbol for every distinct string a client sends, including values you intend to reject on the next line, the classic symbol-DoS vector. This only ever returns a symbol already present in allowed_symbols (or default), so attacker input can never create a new symbol regardless of what is sent.

Degrade-vs-raise is decided by the REQUEST METHOD:

  • GET/HEAD: unrecognised values quietly degrade to default — crawlers and bots probe read endpoints with garbage, and a filter page must not 500 on ?mode=garbage.
  • Mutating requests (POST/PATCH/PUT/DELETE): a PRESENT-but-unrecognised value raises UnrecognizedValue (see above) — this is how a forgotten allow-list entry announces itself instead of hiding. Blank/missing values fall through to default quietly on EVERY method (forms legitimately post no value; no symbol's string form is blank).

allowed_symbols may also contain strings (e.g. a Rails enum's .keys) — the matched entry is symbolized on the way out, so the return value is ALWAYS a symbol (or default). That to_sym runs only on the developer-controlled list entry, never on value, so the DoS-safety above is unaffected.



38
39
40
41
42
43
44
45
46
47
48
49
# File 'app/controllers/concerns/glib/params/allowlist.rb', line 38

def glib_allowlist_symbol_param(value, allowed_symbols, default:)
  match = allowed_symbols.find { |symbol| symbol.to_s == value.to_s }&.to_sym
  return match if match

  if value.present? && !request.get? && !request.head?
    raise UnrecognizedValue,
          "Unrecognised #{request.request_method} param value #{value.to_s.truncate(80).inspect} " \
          "(allowed: #{allowed_symbols.map(&:to_sym).inspect})"
  end

  default
end