Skip to content

mongo passthrough secrets with no binder slot (proxyPassword, TLS key material, passphrases) stay writable as at-rest cleartext — redacted on read since #9040, but the store-side half has no door #9124

Description

@os-zhuang

Found while implementing #9040 (the options.auth.password refusal); filed rather than widened there, because these keys fail the refusal's own remedy test.

What was measured (mongodb@7.5.0, the client @objectstack/driver-mongodb spreads config.options into)

Four MongoClient options are honoured client secrets an author can write into the options passthrough:

  • proxyPassword — SOCKS5 proxy password, accepted and honoured (measured: c.options.proxyPassword carries it).
  • tlsCertificateKeyFilePassword — key-file passphrase, declared in the client's OPTIONS table.
  • key — TLS private key material (PEM), declared in the client's OPTIONS table.
  • passphrase — TLS key passphrase, declared in the client's OPTIONS table.

Why #9040 did NOT refuse them

The datasource secret binder injects exactly ONE secret per datasource, and that slot is the login password (external.credentialsRef resolution). A publish-door refusal of these keys would name a remedy that cannot work and remove the only way to configure an authenticated SOCKS5 proxy or a passphrase-protected key — the same posture as turso's still-writable encryptionKey (#8078; binder-slot expansion is #8081 scope item 4 and was explicitly not decided there either).

What #9040 did do

They are redacted on every read exit (PASSTHROUGH_SECRET_PATHS in packages/spec/src/data/datasource-credential-redaction.ts, with the restore mirror in service-datasource), so they are no longer SERVED in cleartext. The store-side half remains: the values sit cleartext in sys_metadata, written by an authoring path the platform accepts without comment — the exact residual-risk shape #8082's ruling declined for the login password.

The decision this needs (not taken in #9040)

Whether the binder grows named secret slots (covering turso encryptionKey + these four in one mechanism — #8081 item 4's question, generalized), or the platform accepts the at-rest residual risk for non-login secrets, or refuses them without a working remedy. Each option trades differently on capability vs. at-rest exposure; the #9040 PR body carries the per-key measurements.

Backlink: #9040, #8081.


Generated by Claude Code

Activity

  1. os-project-manager commented on Aug 16, 2026

    @os-project-manager
    Collaborator

    Finding first-touch grading (triage seat): escalated to the decision inbox — finding → needs-user-decision + domain:services (the binder and its restore mirror live in service-datasource; the mongo driver family is not where a fix lands, so the #5499 investment freeze is not triggered), type Feature.

    Why this cannot be graded into the queue: the three candidate dispositions are mutually exclusive, each was explicitly declined by the adjacent rulings (#8082 declined the residual-risk posture for the login password only; #9040 declined refusing keys whose refusal names a non-working remedy; #8081 closed with its item 4 — binder-slot expansion — recorded as undecided), and the choice sits on a security boundary, which is manual-floor territory regardless of prism alignment.

    The decision: for the four honoured mongo client secrets writable via options passthrough (proxyPassword, tlsCertificateKeyFilePassword, key, passphrase) — and turso's encryptionKey, same shape — pick one:

    Four-prism:

    • Platform long-term coherence — A is the coherent end-state: one binder mechanism, no per-key exceptions; B leaves a documented inconsistency (login secret bound, sibling secrets cleartext); C violates the refusal-names-a-working-remedy invariant mongo config.options.auth.password is a fourth spelling of an inline credential — authorable, persisted cleartext, unredacted, and read by the client #9040 itself honoured.
    • Measured business pull — zero measured today: no first-party example or known deployment uses an authenticated SOCKS5 proxy or passphrase-protected TLS key material through the passthrough (the keys were found by census, not by a user).
    • AI-agent error-resistance — B is the weakest (silent acceptance of a secret-shaped write is the quiet-tolerance shape); A and C both give the authoring path a loud, correct answer.
    • Startup scope discipline — A is a permanent capability + maintenance obligation bought against zero pull; B is the cheapest standing posture; C is cheap but subtracts a capability the client library genuinely honours.

    Recommendation: B now, with A as the recorded route when pull materialises — accept-and-document the non-login residual risk (one sentence in the datasource security docs naming the four keys), and record that the first real deployment needing an authenticated proxy or key passphrase converts this card into the binder-slot programme (A). Prisms do not all point one way (coherence favours A), and the boundary is security — hence your inbox rather than auto-adjudication.


    Generated by Claude Code

  2. os-zhuang commented on Aug 17, 2026

    @os-zhuang
    ContributorAuthor

    Maintainer ruling (2026-08-17, recorded by PM session session_01NYgmGheCzM6NrHZN436Cxf). The maintainer reviewed the decision-inbox report's six new cards and accepted the recommendations in full, verbatim: 「新进卡六张 同意你的建议」. For this card:

    Ruled: Option B now — accept-and-document the at-rest residual risk for non-login secrets; Option A (named binder slots) is the recorded route when pull materialises.

    Label flipped needs-user-decision → pm:queue (docs deliverable) in the same stroke.


    Generated by Claude Code

  3. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator

    Claim — PM dispatch seat, session session_01Y26DJEHSBhhAQ6wwfsHNza, branch claude/issue-9124-mongo-passthrough-at-rest-doc.

    Dispatching on the 03:19Z maintainer ruling: Option B — accept-and-document. Deliverable is the docs statement naming the four mongo options-passthrough keys plus turso's encryptionKey, and the recorded restart condition that converts this into the binder-slot programme (A).

    ⛔ Scope fence for the implementer: this is a documentation deliverable. Do not add a publish-door refusal (that is Option C, explicitly rejected per #9040's refusal-names-a-working-remedy invariant), and do not grow the binder (that is A, held for measured pull).


    Generated by Claude Code

  4. added a commit that references this issue on Aug 17, 2026
    5dd33dd
  5. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator
    {
      "issue": 9124,
      "status": "done",
      "branch": "claude/issue-9124-mongo-passthrough-at-rest-doc",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9253",
      "premise_still_valid": true,
      "summary": "Implemented the maintainer's Option B ruling (accept-and-document) as a docs-only change: a new subsection in content/docs/data-modeling/drivers.mdx names the four mongo options-passthrough keys (proxyPassword, tlsCertificateKeyFilePassword, key, passphrase) plus turso's encryptionKey, states they are writable and stored at rest in sys_metadata as plain text, credits #9040's read-side redaction as the only protection today, and records the named restart condition (first real deployment needing an authenticated SOCKS5 proxy or passphrase-protected key converts this into the binder-slot programme, Option A). Verified every premise before writing: PASSTHROUGH_SECRET_PATHS in packages/spec/src/data/datasource-credential-redaction.ts covers exactly these keys, the restore mirror (restoreRedactedConfig) lives in service-datasource wired into datasource-admin-service.ts, turso's encryptionKey is a genuinely-writable top-level config key (same at-rest/redacted-on-read outcome shape, different code path from mongo's nested passthrough list), and sys_metadata is confirmed as the real durable storage table. No runtime code touched; Option A (binder slots) and Option C (publish-door refusal) stayed out of scope per the scope fence.",
      "tests": "Documentation-only change; no test suite applies. Local gates derived via `node scripts/pm/dispatch-gates.mjs content/docs/data-modeling/drivers.mdx`, all green at commit 5dd33ddd0142131fd30b43bbcec7d749ec4285b1 (git rev-parse --short HEAD = 5dd33ddd0): `pnpm check:nul-bytes` (OK, 6041 files scanned, no control bytes), `pnpm check:docs-audit-scope` (OK, 178 hand-written docs in sync), `pnpm check:docs-redirects` (OK, 92 entries resolved), `pnpm check:role-word` (OK, 43 baselined files, no new occurrences) at repo root; `pnpm --filter @objectstack/spec run check:empty-state` (OK, all classified), `check:liveness` (green -- pre-existing unregistered-dogfood-proof-tag warnings are informational and unrelated to this change), `check:strictness-ledger` (OK), `check:variant-docs` (OK, 18 discriminated unions governed/exempt) in packages/spec, since content/docs/** is a CI trigger path in spec-liveness-check.yml. packages/spec was built first (pnpm --filter @objectstack/spec build, exit 0) per the toolchain-trap note; gen:schema/gen:openapi produced no diff since no spec source changed. CI on PR #9253 is in_progress at report time -- not waited on per the draft-PR-time reporting contract.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #9254: the auto-generated `options` field description in packages/spec/src/data/driver/mongo.zod.ts (rendered into content/docs/references/data/driver-mongo.mdx and the Studio connection-form help text) overstates the write-side refusal -- it reads \"credential material is refused\", true only for options.auth.password, not for the four keys this card documents. Not fixed in-place: it is a packages/spec source edit pulling in a different (build/docs-regen) verification surface than this docs-only PR."
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  6. added 2 commits that reference this issue on Aug 17, 2026
    2d11ddb
    e4e5c6e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions