Skip to content

pgwire: default Trust auth mode accepts connections for non-existent users with any password #30

@hollanf

Description

@hollanf

Summary

With the default auth configuration (AuthMode::Trust, the built-in default from nodedb/src/config/auth.rs:200), any pgwire client can authenticate as any username — including usernames that were never created via CREATE USER — with any password (including empty). Declared user passwords (CREATE USER alice WITH PASSWORD 'x') are silently ignored in Trust mode. docs/security/auth.md doesn't mention Trust mode exists.

Environment

  • NodeDB v0.0.2, nodedb-0.0.2-linux-arm64 release binary
  • Running in OrbStack Ubuntu ARM64 VM, pgwire on 127.0.0.1:6432
  • Source HEAD for analysis: b024c560
  • No nodedb.toml configured — using built-in defaults
  • Client: postgres.js via Bun

Reproduction

import postgres from 'postgres';

async function tryConnect(user: string, pw: string) {
  const s = postgres({ host: '127.0.0.1', port: 6432, user, password: pw,
    database: 'moomoori', prepare: false, fetch_types: false, max: 1 });
  const r = await s.unsafe('SELECT 1 AS x');
  console.log(user, pw, '->', r);
  await s.end();
}

// user was created with: CREATE USER alice WITH PASSWORD 'strong_real_pw_123' ROLE readwrite TENANT 1
await tryConnect('alice', 'strong_real_pw_123');   // accepted (expected)
await tryConnect('alice', 'wrong_password');        // accepted (unexpected)
await tryConnect('alice', '');                       // accepted (unexpected)
await tryConnect('nosuchuser_ever_created', 'anything');  // accepted (unexpected)

All four connections succeed and return [{ x: 1 }].

Expected

At minimum, Trust mode should still verify the connecting username corresponds to a known user (matches PostgreSQL's trust method behavior — it skips password verification but still resolves the role from pg_roles). Right now any fabricated username is accepted and presumably operates under some default identity.

Ideally also:

  • docs/security/auth.md documents that Trust is the default and what it means
  • Or the default shifts to a mode that requires existence (SCRAM with a mandatory NODEDB_SUPERUSER_PASSWORD env var on first boot, etc.)

Actual

  • Non-existent usernames authenticate successfully.
  • Any password (including empty) authenticates successfully for existing users.
  • Declared WITH PASSWORD '...' is dead metadata under Trust mode.
  • docs/security/auth.md advertises SCRAM-SHA-256 as the password-auth method but never mentions Trust mode being the default.

Source pointers

  • nodedb/src/config/auth.rs:200AuthMode::Trust is the default in AuthConfig::default().
  • nodedb/src/control/server/pgwire/factory.rs:179-180 — when AuthMode::Trust, startup handler is AuthStartup::Trust which just proceeds.
  • nodedb/src/control/server/pgwire/factory.rs:246-263 — the Trust branch of on_startup records an audit line ("trust auth: {username}") and returns Ok(()) without consulting credentials / the user catalog.

Related

Combined with issue #29 (tenant-scoped CREATE COLLECTION planner mismatch), this makes it hard to isolate multi-tenant deployments even when operators do everything "by the book" — running the default binary with CREATE TENANT + CREATE USER WITH PASSWORD doesn't produce the isolation the docs imply.

Also, CREATE TENANT acme auto-creates an acme_admin user with no password set. That's fine under Trust mode (password irrelevant), but becomes a latent zero-password account if operators later flip to AuthMode::Password.

Metadata

Metadata

Assignees

No one assigned

    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