Skip to content

Auth.all() bypasses schema validation for OPENCODE_AUTH_CONTENT and silently swallows JSON parse errors #34075

Closed as not planned

Description

@1volt12

Description

In packages/opencode/src/auth/index.ts, the Auth.all() function has two code paths for loading auth data: a file-based path that applies schema validation via Record.filterMap(decode), and an env-var path (OPENCODE_AUTH_CONTENT) that returns JSON.parse(...) directly without validation. JSON parse errors are also silently swallowed by an empty catch block, falling through to the file path even though the user explicitly set the env var. The result is that malformed OPENCODE_AUTH_CONTENT silently falls back to file-based auth, and invalid auth entries (wrong type, missing fields, non-object values) reach downstream provider code that switches on info.type.

Plugins

None

OpenCode version

1.17.11 (dev branch, commit 6e8e772)

Steps to reproduce

Auth.all() in packages/opencode/src/auth/index.ts has two code paths for loading auth data: a file-based path and an env-var path (OPENCODE_AUTH_CONTENT). The file path applies schema validation via Record.filterMap(decode) to filter out entries that don't conform to the Auth.Info schema. The env-var path returns JSON.parse(...) directly without any validation, and JSON parse errors are silently swallowed by an empty catch block.

Reproduction:

import { Effect } from "effect"
import { Auth } from "../../src/auth"

// Case 1: invalid JSON is silently swallowed, falls through to file read
process.env.OPENCODE_AUTH_CONTENT = "{not valid json"
const data1 = await Effect.runPromise(Auth.all())
// Expected: AuthError indicating the env var is corrupt
// Actual: silently falls through to file-based auth, no error

// Case 2: invalid entry (wrong type) passes through unvalidated
process.env.OPENCODE_AUTH_CONTENT = JSON.stringify({
anthropic: { type: "api", key: "valid-key" },
bad: { type: "unknown_type", key: "x" }, // not a valid Auth.Info
notAnObject: "string",
})
const data2 = await Effect.runPromise(Auth.all())
// Expected: data2.bad and data2.notAnObject are filtered out (matching file-path behavior)
// Actual: data2.bad === { type: "unknown_type", key: "x" }, data2.notAnObject === "string"
// Downstream code that switches on info.type (e.g. provider/auth.ts:167) gets unexpected shapes

delete process.env.OPENCODE_AUTH_CONTENT

Screenshot and/or share link

No response

Operating System

N/A — pure TypeScript code in packages/opencode/src/auth/index.ts. Reproduces on any OS.0

Terminal

N/A — bug is in auth loading logic, not TUI.

Activity

  1. lexlian commented on Jun 30, 2026

    @lexlian

    @1volt12 @StarpTech , I fixed the issue with PR #34654.

    The bug was in packages/opencode/src/auth/index.ts Auth.all(). The env-var path of OPENCODE_AUTH_CONTENT returned JSON.parse(...) directly, bypassing the Record.filterMap(decode) schema validation that the file path applies — so malformed entries (unknown_type, non-object values, missing fields) reached downstream provider code that switches on info.type. The empty catch block silently swallowed JSON parse errors, falling through to file-based auth even though the user had explicitly set the env var.

    The fix replaces the bare try/catch with Effect.try({ try, catch }) to surface parse errors as AuthError, rejects non-object top-level JSON (arrays, primitives, null), and applies the same Record.filterMap(decode) validation that the file path already uses.

  2. github-actions commented on Aug 30, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions