Skip to main content

turso-cli CVE-2026-48790

| EUVDEUVD-2026-56787 MEDIUM
Incorrect Default Permissions (CWE-276)
2026-06-26 https://github.com/tursodatabase/turso-cli GHSA-57f6-pvx8-hwj6
5.5
CVSS 3.1 · Vendor: https://github.com/tursodatabase/turso-cli
Share

Severity by source

Vendor (https://github.com/tursodatabase/turso-cli) PRIMARY
5.5 MEDIUM
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
vuln.today AI
5.5 MEDIUM

Local file read requires an existing local account (AV:L, PR:L); 0o644 default needs no special conditions (AC:L); credential theft yields full confidentiality loss with no integrity or availability impact on the local system.

3.1 AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
4.0 AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N
SUSE
MEDIUM
qualitative

Primary rating from Vendor (https://github.com/tursodatabase/turso-cli).

CVSS VectorVendor: https://github.com/tursodatabase/turso-cli

Attack Vector
Local
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

Lifecycle Timeline

3
Source Code Evidence Fetched
Jun 26, 2026 - 21:21 vuln.today
Analysis Generated
Jun 26, 2026 - 21:21 vuln.today
CVE Published
Jun 26, 2026 - 20:44 github-advisory
MEDIUM 5.5

DescriptionCVE.org

Summary

turso-cli persists the user's Turso platform JWT to settings.json using Viper's default configPermissions of 0o644, leaving the credential file world-readable on standard Linux and macOS systems. Any other local UID on the host can read the file and recover the platform JWT, which grants full Turso platform access scoped to the user's organizations.

Impact

The token in settings.json grants the holder full Turso platform access - create or destroy databases, rotate credentials, exfiltrate data, change billing settings - for any organization the user belongs to.

Because the file is world-readable, the credential is reachable by:

  • Cron jobs or daemons running as a different system user on the same host
  • Sandboxed CI runners with a mounted home directory
  • Containers with a bind-mounted host home
  • Co-tenants on a shared multi-user developer or jumpbox host

The file path resolves through configdir.LocalConfig("turso"):

  • macOS: ~/Library/Application Support/turso/settings.json
  • Linux: ~/.config/turso/settings.json (or $XDG_CONFIG_HOME/turso/settings.json)

It contains the platform JWT in plaintext JSON alongside organization and username fields.

Comparable CLIs (gh, aws, docker, gcloud, plus close peers planetscale, neon, upstash) write credential files at 0o600 explicitly, so this is a deviation from the cross-vendor baseline rather than a deliberate trade-off.

Details

The OAuth callback handler stores the platform JWT via the settings layer:

go
// internal/cmd/auth.go:205-214
jwt, err := callbackServer.Result()
...
settings.SetToken(jwt)

SetToken writes through Viper:

go
// internal/settings/settings.go:124-127
func (s *Settings) SetToken(token string) {
    viper.Set("token", token)
    s.changed = true
}

Persistence runs through viper.WriteConfig:

go
// internal/settings/settings.go:96-101
func TryToPersistChanges() error {
    if err := viper.WriteConfig(); err != nil {
        return fmt.Errorf("failed to persist turso settings file: %w", err)
    }
    return nil
}

Viper v1.21.0 (pinned in turso-cli go.mod) initializes configPermissions to os.FileMode(0o644) at viper.go:198 and passes that mode straight to os.OpenFile at viper.go:1688. Without a call to viper.SetConfigPermissions(0o600), the resulting settings.json is created at 0o644.

A grep over the auth-config write path under internal/ returns zero hits for Chmod, 0o600, or 0600, confirming there is no follow-up tightening of the file mode anywhere on the persistence path.

Proof of concept

Minimal reproducer using the same Viper version turso-cli pins (github.com/spf13/viper v1.21.0):

go
package main

import (
    "fmt"
    "os"
    "path/filepath"

    "github.com/spf13/viper"
)

func main() {
    dir, _ := os.MkdirTemp("", "viperpoc-*")
    defer os.RemoveAll(dir)

    viper.SetConfigName("settings")
    viper.SetConfigType("json")
    viper.AddConfigPath(dir)

    viper.Set("token", "FAKE_TURSO_JWT_xxxxxxxxxxxxxxxxxxxx")
    viper.Set("organization", "exampleorg")
    viper.SafeWriteConfig()

    st, _ := os.Stat(filepath.Join(dir, "settings.json"))
    fmt.Printf("mode: %o\n", st.Mode()&0o777)
}

$ go run main.go mode: 644

The same SafeWriteConfig / WriteConfig calls turso-cli uses produce the same 0o644 mode in a real turso auth login flow.

Remediation

One-line fix at the existing Viper configuration site in internal/settings/settings.go (around lines 48-50):

go
viper.SetConfigName("settings")
viper.SetConfigType("json")
viper.AddConfigPath(configPath)
viper.SetConfigPermissions(0o600) // restrict settings.json to owner only

Defense in depth:

  • Add os.Chmod(configFile, 0o600) after TryToPersistChanges, or on read (as PlanetScale does in internal/config/config.go - they Stat the token file and self-heal if Mode() &^ 0o600 is nonzero). viper.SetConfigPermissions applies only on file creation, so an existing wider-mode file is not tightened otherwise.
  • Add os.Chmod(configPath, 0o700) after configdir.MakePath(configPath) (line 43) to close the equivalent gap on the enclosing directory, which is otherwise created under the default umask.

Patch: https://github.com/tursodatabase/turso-cli/commit/ffb914849216ef5a86353b3fa6cee66f33af3b66

Workarounds

Until upgraded, users can tighten the existing files manually:

sh
# Linux
chmod 600 ~/.config/turso/settings.json
chmod 700 ~/.config/turso
# macOS
chmod 600 "$HOME/Library/Application Support/turso/settings.json"
chmod 700 "$HOME/Library/Application Support/turso"

This must be repeated after any operation that recreates the file (e.g. turso auth login) until the patched version is installed.

Resources

  • Patch commit: https://github.com/tursodatabase/turso-cli/commit/ffb914849216ef5a86353b3fa6cee66f33af3b66
  • Viper configPermissions default: https://github.com/spf13/viper/blob/v1.21.0/viper.go#L198
  • Viper write path: https://github.com/spf13/viper/blob/v1.21.0/viper.go#L1688
  • CWE-276: https://cwe.mitre.org/data/definitions/276.html
  • CWE-732: https://cwe.mitre.org/data/definitions/732.html

AnalysisAI

Credential exposure in turso-cli versions 1.0.25 and earlier allows any local user on the same host to read the Turso platform JWT stored world-readable at mode 0o644 in settings.json, granting full access to all Turso organizations the victim belongs to. The root cause is turso-cli's failure to override Viper's insecure default configPermissions before writing credentials - a deviation from the explicit 0o600 baseline established by comparable CLIs including gh, aws, docker, and gcloud. A proof-of-concept demonstrating the 0o644 mode is included in the advisory; no active exploitation is listed in CISA KEV.

Technical ContextAI

turso-cli is a Go-based command-line tool for the Turso hosted SQLite platform, using the Viper configuration library (v1.21.0, pinned in go.mod) for settings persistence. Viper initializes its internal configPermissions field to os.FileMode(0o644) at viper.go:198 and passes this mode directly to os.OpenFile at viper.go:1688 when writing config files. The turso-cli auth flow captures the platform JWT in the OAuth callback (internal/cmd/auth.go:205-214), writes it via viper.Set('token', jwt) through the settings layer (internal/settings/settings.go:124-127), and persists it with viper.WriteConfig() (internal/settings/settings.go:96-101) - without ever calling viper.SetConfigPermissions(0o600) to override the insecure default. A code audit confirmed zero occurrences of Chmod, 0o600, or 0600 on the auth-config write path under internal/. CWE-276 (Incorrect Default Permissions) is the primary root cause, with CWE-732 (Incorrect Permission Assignment for Critical Resource) also applicable given the credential nature of the file. The affected package is pkg:go/github.com/tursodatabase/turso-cli at versions <= 1.0.25.

RemediationAI

Upgrade turso-cli to version 1.0.26, which includes the vendor-released patch at https://github.com/tursodatabase/turso-cli/commit/ffb914849216ef5a86353b3fa6cee66f33af3b66, adding viper.SetConfigPermissions(0o600) to the Viper initialization block in internal/settings/settings.go. Critically, viper.SetConfigPermissions applies only on file creation - existing settings.json files with 0o644 mode are not automatically tightened by upgrading alone. After upgrading, run chmod 600 ~/.config/turso/settings.json && chmod 700 ~/.config/turso on Linux, or chmod 600 "$HOME/Library/Application Support/turso/settings.json" && chmod 700 "$HOME/Library/Application Support/turso" on macOS. This manual step must also be repeated after any turso auth login that recreates the file on an unpatched installation. As defense in depth, the vendor advisory recommends also adding os.Chmod(configFile, 0o600) after TryToPersistChanges to self-heal pre-existing files with overly broad modes, following the pattern used by the PlanetScale CLI.

More in Docker

View all
CVE-2024-55964 CRITICAL POC
9.8 Mar 26

An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl

CVE-2019-5736 HIGH POC
8.6 Feb 11

runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac

CVE-2023-32077 HIGH POC
7.5 Aug 24

Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2023-5815 HIGH POC
8.1 Nov 22

The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post

CVE-2026-66384 MEDIUM POC
5.3 Aug 12

Path traversal in JFrog Artifactory (CWE-22) enables an authenticated low-privilege user to write data outside the inten

CVE-2014-9357 CRITICAL
10.0 Dec 16

Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build

CVE-2026-52806 CRITICAL POC
9.9 Jun 23

Remote code execution in Gogs through 0.14.2 allows authenticated users (and unauthenticated attackers on default-config

CVE-2026-56274 HIGH POC
8.7 Jun 23

Remote code execution in Flowise before 3.1.2 allows any authenticated user (or API caller with chatflow view/update per

CVE-2026-34156 CRITICAL POC
9.9 Mar 30

Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l

CVE-2019-15752 HIGH POC
7.8 Aug 28

Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c

CVE-2025-34221 CRITICAL POC
10.0 Sep 29

Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2

Vendor StatusVendor

SUSE

Severity: Moderate
Product Status
SUSE Linux Enterprise Server 16.1 Affected
SUSE Linux Enterprise Server for SAP applications 16.1 Affected
SUSE Linux Enterprise Module for Package Hub 15 SP5 Affected
SUSE Linux Enterprise Module for Package Hub 15 SP6 Affected
openSUSE Leap 15.5 Affected

Share

CVE-2026-48790 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy