---
id: CVE-2026-105963
title: >-
  Secret key base exposed in stack trace arguments on wrong-typed Plug.Crypto
  arguments
summary: >-
  Externally-Generated Error Message Containing Sensitive Information
  vulnerability in plug_crypto in elixir-plug plug_crypto allows an
  unauthenticated remote attacker to expose the secret key base through
  application logs via a wrong-type…
severity: medium
cvss: 5.1
cvssVector: 'CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N'
cvssSource: cna
cwe:
  - CWE-532
vendor: elixir-plug
product: plug
affected:
  - plug >= 1.6.3 < 1.7.0
  - elixir-plug/plug >= 56000c33d8a0a2fbac491f8be06b9c5112bc2276 < *
  - plug_crypto >= 1.0.0 < 2.2.1
  - >-
    elixir-plug/plug_crypto >= 2d078b7b8264c565f0ff71235c515f4f46882dcf <
    981887493dada0fce7003c61861c00dfbb0fc8c5
ssvc:
  exploitation: none
  automatable: 'no'
  technicalImpact: partial
  timestamp: '2026-10-23T10:53:00.474296Z'
published: '2026-10-23'
updated: '2026-10-23'
sourceUpdated: '2026-10-23T13:39:29.887Z'
source: CVEORG
sourceUrl: 'https://www.cve.org/CVERecord?id=CVE-2026-105963'
references:
  - url: >-
      https://github.com/elixir-plug/plug/security/advisories/GHSA-ffw9-w85g-f2vh
    label: >-
      Secret key base exposed in stack trace arguments on wrong-typed
      Plug.Crypto arguments
  - url: 'https://cna.erlef.org/cves/CVE-2026-105963.html'
    label: EEF CNA record for CVE-2026-105963
  - url: 'https://osv.dev/vulnerability/EEF-CVE-2026-105963'
    label: OSV record EEF-CVE-2026-105963
  - url: >-
      https://github.com/elixir-plug/plug/commit/56000c33d8a0a2fbac491f8be06b9c5112bc2276
    label: Introducing commit 56000c3 in elixir-plug/plug
  - url: >-
      https://github.com/elixir-plug/plug/commit/aeaa90e76b73ea90c3ecca9aae16fce71bd2a8d4
    label: Fix commit aeaa90e in elixir-plug/plug
  - url: >-
      https://github.com/elixir-plug/plug_crypto/commit/2d078b7b8264c565f0ff71235c515f4f46882dcf
    label: Introducing commit 2d078b7 in elixir-plug/plug_crypto
  - url: >-
      https://github.com/elixir-plug/plug_crypto/commit/981887493dada0fce7003c61861c00dfbb0fc8c5
    label: Fix commit 9818874 in elixir-plug/plug_crypto
tags:
  - cve.org
ingestedAt: '2026-10-23T10:21:59.182Z'
---

## Overview

Externally-Generated Error Message Containing Sensitive Information vulnerability in plug_crypto in elixir-plug plug_crypto allows an unauthenticated remote attacker to expose the secret key base through application logs via a wrong-typed argument. Every public function in Plug.Crypto validates argument types in a function-head guard. A failed guard makes the Erlang VM raise FunctionClauseError with the actual argument values in the top stack frame, so the secret key base, a derived key, or the value an API key is compared against lands in that frame. The library's rescue blocks and Plug.Crypto.prune_args_from_stacktrace/1 only reach exceptions raised inside a function body, so they never see a guard failure. Plug.Cowboy and Bandit write the frame to the error log and attach it as crash_reason Logger metadata, which error trackers forward.

Two entry points take request data. Plug.Crypto.verify/4 exposes the secret key base when the token is neither a binary nor nil, which Phoenix.Token.verify/4 reaches because it forwards the token unguarded. Plug.Crypto.secure_compare/2 exposes the other operand when one side is not a binary, as happens when a missing request header yields nil. Reading the leaked value needs separate access to the logs or the error tracker, so the request alone does not disclose the secret to the attacker.

This issue affects plug: from 1.6.3 before 1.7.0; plug_crypto: from 1.0.0 before 2.2.1.

## Affected

- `plug >= 1.6.3 < 1.7.0`
- `elixir-plug/plug >= 56000c33d8a0a2fbac491f8be06b9c5112bc2276 < *`
- `plug_crypto >= 1.0.0 < 2.2.1`
- `elixir-plug/plug_crypto >= 2d078b7b8264c565f0ff71235c515f4f46882dcf < 981887493dada0fce7003c61861c00dfbb0fc8c5`

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.

### Workarounds

Check argument types in the calling code before entering Plug.Crypto, so no head guard ever fails. Pass a token to Phoenix.Token.verify/4, Phoenix.Token.decrypt/4, Plug.Crypto.verify/4 or Plug.Crypto.decrypt/4 only when is_binary(token) holds, and treat anything else as an invalid token. Call Plug.Crypto.secure_compare/2 only when both operands are binaries, treating a missing header or parameter as a failed comparison rather than passing nil.

Where the leaked value matters more than the crash, configuring the error tracker to drop stack-frame arguments also keeps the secret out of the forwarded report. For Sentry this means not sending vars with the crash report. This narrows exposure but leaves the value in the local error log.
