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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions