Skip to content

In-memory (plain CREATE SECRET) user secrets linger across sessions on a reused worker #766

Description

@fuziontech

Problem

Found while writing a customer-runnable test script for #752 against mw-prod-us: a plain (in-memory) CREATE SECRET issued in session A is still visible in session B whenever B reuses the same hot-idle worker — empirically reproduced on a prod duckling. Since hot-idle reuse spans users of the same org, user A's in-memory secret (with live credential material) is readable by user B via duckdb_secrets() and usable by scope match.

This is pre-existing behavior, not a #752 regression: DuckDB secrets are instance-global, and the #752 session-start hygiene wipe deliberately clears only persistent-storage secrets, because the system catalog secrets (ducklake_s3, iceberg_sigv4, iceberg_oauth) are in-memory and must survive. Before #752 the same lingering applied to persistent secrets too (worse); the in-memory half of the gap remains.

Reproduce

psql ... -c "CREATE SECRET t1 (TYPE s3, KEY_ID 'x', SECRET 'y')"
psql ... -c "SELECT name FROM duckdb_secrets() WHERE name='t1'"   # new session, reused worker → t1

Proposed fix

Extend wipeUserPersistentSecrets (duckdbservice/user_secrets.go) into a full user-secret wipe at session create: drop all secrets — any storage — whose name is not reserved (usersecrets.IsReservedName covers the system set + __default_*/duckgres_* prefixes). The reserved-name guard already exists and is already load-bearing for CREATE interception; reusing it here keeps one source of truth. Same one-session-per-worker precondition assertion applies.

Caveat to check: unnamed user secrets get DuckDB default names (__default_s3), which collide with the reserved prefix — wiping them is correct (they're user-created), so the wipe predicate should be "not a system secret name" rather than IsReservedName verbatim; may need to split the reserved set (system names vs reserved-for-create prefixes).

The e2e persistent_user_secret_isolation assertion in tests/e2e-mw-dev/harness.sh should gain a temp-secret leg (user A CREATE SECRET; user B must not see it).

🤖 Generated with Claude Code

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