HIGH formula injectionchijwt tokens

Formula Injection in Chi with Jwt Tokens

Formula Injection in Chi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Formula Injection occurs when user-controlled data is interpreted as a formula by spreadsheet or document processing libraries, causing unintended evaluation. When this vulnerability intersects with JWT token handling in Chi, a web framework for the Elixir ecosystem, the risk pattern changes because tokens often contain structured payloads that may be transformed or logged.

In Chi, developers commonly parse and validate JWT tokens using libraries such as joken or guardian. If a token’s payload (e.g., claims such as email, roles, or session identifiers) is later embedded into generated spreadsheets, CSVs, or documents without proper sanitization, an attacker-controlled claim can be interpreted as a formula. For example, an email claim like =cmd|' /C calc'!A0 stored in a user profile and later written into an exported Excel file could trigger arbitrary command execution on the server when the file is opened.

This becomes a JWT-specific concern because tokens are often base64-encoded JSON with a signature, and developers may mistakenly trust the decoded payload without validating or escaping its contents. If a Chi application decodes a JWT, extracts a field such as name, and uses it directly in a spreadsheet generation routine (e.g., via scrivener_ecto or elixir_excel), unescaped equals signs or structured injection patterns can lead to formula injection. The attack surface is not the token signature verification itself, but the downstream handling of token claims in report generation, export features, or administrative dashboards where data from the token is rendered into files that are later consumed by end users.

Additionally, attackers may attempt to inject formulas through token metadata if a Chi API accepts query parameters that influence which token claims are included in exported data. For instance, a parameter such as ?fields=name,email that maps directly to JWT payload fields could be abused to include malicious payloads if the application does not strictly whitelist allowed fields. The intersection of JWT usage and document generation increases the importance of validating, encoding, and sanitizing any data originating from the token before it reaches spreadsheet or document processing code.

Real-world patterns include using JWT claims in CSV exports where a leading equals sign triggers formula evaluation in spreadsheet software, or embedding tokens’ session identifiers into HTML exports that are later opened in Office applications. Because tokens are designed for secure transport and authentication, developers may overlook the need to treat their contents as untrusted input when used in reporting or export workflows.

Jwt Tokens-Specific Remediation in Chi — concrete code fixes

Remediation focuses on strict validation, output encoding, and separation of concerns between authentication and data rendering. Never directly embed JWT payload fields into files or documents without sanitization. Use allowlists for expected fields and encode values according to the target format (e.g., CSV, Excel, HTML).

Example 1: Validating and sanitizing JWT claims before export in Chi

defmodule MyApp.ReportGenerator do
  import NimbleCSV.RFC4180, only: [encode_row: 1]

  @allowed_fields ~w(email name role)a

  def build_csv(claims) do
    # Whitelist only safe fields from the JWT claims
    sanitized = @allowed_fields
                |> Enum.map(&Map.get(claims, &1, ""))
                |> Enum.map(&sanitize_cell/1)

    # Generate safe CSV rows
    [ ["Email", "Name", "Role"] | [sanitized] ]
    |> NimbleCSV.RFC4180.encode_to_iodata()
  end

  defp sanitize_cell(value) when is_binary(value) do
    # Remove leading equals signs and trim dangerous characters
    cleaned = String.replace_prefix(value, "=", "'")
    String.trim(cleaned)
  end
  defp sanitize_cell(_), do: ""
end

Example 2: Secure JWT verification and controlled data exposure in Chi router

defmodule MyAppWeb.ApiController do
  use MyAppWeb, :controller
  import MyAppWeb.Auth, only: [current_user: 1]

  # Only expose explicitly allowed fields from the JWT
  def export_user_data(conn, _params) do
    claims = current_user(conn)
             |> Map.take(["email", "name", "role"])

    csv_data = MyApp.ReportGenerator.build_csv(claims)
    send_resp(conn, 200, csv_data)
  end
end

Example 3: Using Joken for safe token validation and claim extraction

defmodule MyApp.Auth do
  use Joken.Config

  def current_user(conn) do
    with [token] <- Plug.Conn.get_req_header(conn, "authorization"),
         {:ok, claims} <- verify_and_validate(token) do
      claims
    else
      _ -> %{}
    end
  end

  defp verify_and_validate(token) do
    # Configure validator with your secret and expected claims
    default_claims()
    |> Joken.Config.add_claim("email", & &1, &is_binary/1)
    |> Joken.Config.add_claim("role", & &1, &is_binary/1)
    |> Joken.verify_and_validate(token, Joken.Signer.create("HS256", "your-secret"))
  end
end

Example 4: Escaping formulas in Excel generation with XlsxWriter

defmodule MyApp.ExcelReport do
  use XlsxWriter.Workbook

  def generate(claims) do
    workbook = XlsxWriter.Workbook.new("report.xlsx")
    worksheet = XlsxWriter.Workbook.add_worksheet(workbook)

    email = Map.get(claims, "email", "")
    # Prefix single quotes to prevent formula interpretation
    safe_email = if String.starts_with?(email, "="), do: "'" <> email, else: email

    worksheet.write_string(0, 0, safe_email)
    XlsxWriter.Workbook.close(workbook)
  end
end

Example 5: Enforcing field allowlists in Chi pipeline

defmodule MyAppWeb.Plugs.SanitizeJwtClaims do
  import Plug.Conn

  @allowed ~w(sub email role iat exp)a

  def init(opts), do: opts

  def call(conn, _opts) do
    case get_session(conn, :jwt_claims) do
      nil -> conn
      claims ->
        sanitized = Enum.reduce(@allowed, %{}, fn key, acc ->
          if Map.has_key?(claims, key) do
            Map.put(acc, key, sanitize_value(claims[key]))
          else
            acc
          end
        end)
        assign(conn, :safe_claims, sanitized)
    end
  end

  defp sanitize_value(value) when is_binary(value) do
    String.replace_prefix(value, "=", "'")
  end
  defp sanitize_value(value), do: value
end

Frequently Asked Questions

How does formula injection differ from typical injection attacks like SQLi or XSS?
Formula injection exploits the interpretation of input as executable expressions in spreadsheet or document processors, whereas SQL injection targets database queries and XSS targets browser rendering. In Chi, JWT claims that reach export or reporting logic must be treated as potentially executable data.
Does middleBrick detect formula injection risks in JWT payloads exported from Chi applications?
middleBrick scans API endpoints and can identify exposed endpoints that export JWT-derived data without proper sanitization, providing findings with severity and remediation guidance. Use the CLI (middlebrick scan ) or Web Dashboard to track these risks across your API surface.