Skip to content

Bump toolchain to Elixir 1.18.5-otp-27, fix critical grpc RCE and other pre-existing CVEs - #184

Open
erinxocon wants to merge 9 commits into
masterfrom
otp27-runtime-bump
Open

erinxocon wants to merge 9 commits into
masterfrom
otp27-runtime-bump

Conversation

@erinxocon

Copy link
Copy Markdown
Member

Description

Bumps the runtime from Elixir 1.14.3-otp-25/Erlang 25.3.2.16 to Elixir 1.18.5-otp-27/Erlang 27.3.4.17. Bundled in are the dependency bumps needed to make that upgrade land cleanly plus fixes for CVEs found in the process.

  1. Bump toolchain to Elixir 1.18.5-otp-27 — CI images, Dockerfile, .tool-versions; Logger.warn/1Logger.warning/2 (deprecated since 1.15); two unreachable clauses removed, surfaced by Elixir 1.18's new type checker
  2. Fix critical grpc RCE — bumps bottle to pull in grpc ~> 1.0 (fixes GHSA-grp7-v8xh-rj7h / CVE-2026-48853) and amqp ~> 4.0; protobuf ~> 0.17 removed the generated Message.new/1 helper, so two call sites move to struct!/2; spandex/spandex_datadog bumped for telemetry compatibility
  3. Swap logger_json to the maintained Hex package — moves off a 2021 git fork to ~> 7.0, adapting config/plug/telemetry to its new :default_handler API
  4. Bump Phoenix 1.7 → 1.8 — 1.7 is EOL; fixes the removed namespace: controller option and adds the new listeners: knob
  5. Fix remaining pre-existing CVEsguardian, httpoison, joken/jose, plug_cowboy, cowboy/cowlib, a hackney ~> 4.0 override, and an ecto/ecto_sql/myxql/decimal unlock chain

Verification

  • mix compile --force --warnings-as-errors clean
  • 160/160 tests passing
  • mix format --check-formatted clean
  • Dev phx.server boots to HTTP 200 with no warnings

Bumps CI images, Dockerfile, and .tool-versions from Elixir
1.14.3-otp-25/Erlang 25.3.2.16 to 1.18.5-otp-27/Erlang 27.3.4.17, and
fixes what the bump itself surfaced with no dependency changes:

- Logger.warn/1 -> Logger.warning/2 (deprecated since Elixir 1.15) at
  4 call sites, plus config :logger, level: :warn -> :warning
- two unreachable clauses removed (fallback_controller.ex,
  user_settings_two_factor_controller.ex), surfaced by Elixir 1.18's
  new type checker; both provably dead, not called anywhere
Pins bottle to system76/bottle@229a577b, which bumps grpc 0.5.0 (< 1.0.0)
to ~> 1.0 to fix a critical RCE (GHSA-grp7-v8xh-rj7h / CVE-2026-48853)
and moves to amqp ~> 4.0 so rabbit_common resolves cleanly on OTP 27
with no version overrides.

grpc ~> 1.0 requires protobuf ~> 0.17, which removed the deprecated
Message.new/1 helper every generated struct used to get for free
(protobuf's own CHANGELOG: deprecated in v0.15.0, removed in v0.17.0).
Recognizer's two call sites switch to struct!/2, matching bottle's own
fix for the same break: lib/recognizer/caster.ex and
lib/recognizer/notifications/account.ex (the latter used
apply(type, :new, [...]) for dynamic dispatch, easy to miss grepping
for a literal ".new(").

Also bumps spandex ~> 3.2 / spandex_datadog ~> 1.4.0: the old versions
capped telemetry at ~> 0.4, incompatible with grpc_core's telemetry
~> 1.0 requirement pulled in by this same bottle bump.
Nebo15/logger_json@8e4290a was pinned to a 2021 git fork (reasonable
at the time -- Hex hadn't seen a release since 2019) but the project
is actively maintained again through 7.0.4 as of Jul 2025. Moves to
{:logger_json, "~> 7.0"}.

7.0's API was redesigned around Elixir's :default_handler model:

- config/config.exs: drops the old `config :logger_json, :backend, ...`
  key, which no longer exists
- config/prod.exs: `backends: [LoggerJSON]` -> `default_handler:
  [formatter: {LoggerJSON.Formatters.Datadog, metadata: :all}]` -- must
  use the {Module, opts} tuple form, not `.new(...)`, since compile-time
  config evaluates before deps are compiled and calling `.new(...)`
  directly deadlocks a from-scratch `_build/prod` boot
- endpoint.ex: removes `plug LoggerJSON.Plug, ...` (no longer a Plug
  module)
- telemetry.ex: attaches LoggerJSON.Plug.telemetry_logging_handler/4
  to the phoenix/endpoint/stop event, replacing what the removed
  endpoint plug used to do, mirroring the existing Ecto handler pattern
The 1.7 branch is EOL (last release Mar 2025); all security fixes
since are 1.8-only. Bumps phoenix ~> 1.7.1 -> ~> 1.8 (1.7.12 -> 1.8.14).

1.8 removed the `namespace:` controller option recognizer's shared
`RecognizerWeb.controller/0` macro used, and now requires an explicit
`:formats` option. Fixed by reading Phoenix's actual source
(__plugs__/2 in phoenix/lib/phoenix/controller.ex) rather than the
compiler warning's suggested snippet, which would raise "no previous
layout set" at the first HTML render:

    use Phoenix.Controller, formats: [html: "View", json: "View"]
    plug :put_new_layout, {RecognizerWeb.LayoutView, :app}

This matches exactly what the old `namespace:` fallback did internally.

Also adds `listeners: [Phoenix.CodeReloader]` to mix.exs -- a new
required knob in 1.8 for the dev code-reloader (was printing a warning
on every dev request otherwise).
Fixes CVEs found in recognizer's own deps while validating the OTP 27
bump above, all pre-existing on master (confirmed via a pre-change
mix.lock diff and a stash round-trip boot test):

- guardian ~> 2.0 -> ~> 2.5 (2.3.2 -> 2.5.0, fixes 3 CVEs incl.
  forged-token revocation)
- httpoison ~> 1.8.2 -> ~> 3.0 (1.8.2 -> 3.0.0; public
  HTTPoison.get/post/%Response{}/%Error{} API unchanged across majors,
  verified against call sites in hal.ex/client.ex)
- joken ~> 2.6.0 -> ~> 2.7, pulling in jose ~> 1.11.12 (fixes the jose
  DoS CVE; jose isn't a direct dep)
- plug_cowboy ~> 2.4 -> ~> 2.9
- cowboy/cowlib overrides ~> 2.8/~> 2.9.1 -> ~> 2.19/~> 2.20 (cowlib
  2.9.1 had 7 CVEs; 2.20.0, the latest upstream release, still carries
  3 unpatched ones -- nothing more to do via version bump)
- hackney override ~> 4.0, needed because ex_aws_sqs's optional
  hackney ~> 1.9 dep conflicts with httpoison 3.0's hackney ~> 4.0
  requirement; recognizer configures http_client: HTTPoison for ExAws
  in every env, so ex_aws_sqs's hackney-based adapter path is dead
  weight, not a real runtime pairing
- decimal (transitive via ecto) was capped at 2.4.1 by myxql being
  stuck at 0.6.3, which capped ecto_sql below the 3.12+ that requires
  myxql ~> 0.8; unlocked myxql/ecto/ecto_sql/decimal together to let
  the whole chain move (myxql 0.6.3->0.9.0, ecto_sql 3.11.3->3.12.1,
  decimal 2.4.1->3.1.1)
@erinxocon
erinxocon requested a review from a team as a code owner September 14, 2026 22:37
credo 1.7.1 crashes on every file under Elixir 1.18 (CaseClauseError:
:elixir_tokenizer.tokenize/3 now returns a 6-tuple). Bumps to 1.7.19,
already allowed by mix.exs's existing ~> 1.5 constraint.
erinxocon and others added 3 commits September 14, 2026 20:54
BigCommerce's Customer Login API spec requires iat (issued-at) on the
signed JWT and only honors the token for 30 seconds after that
timestamp. The claim was missing from jwt_claims/1, even though the
flow currently works without it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants