You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
mongo config.options.auth.password is a fourth spelling of an inline credential — authorable, persisted cleartext, unredacted, and read by the client #9040
Found while implementing #8696's mongodb arm (the DSN-branch secret injection), and filed rather than fixed there: it is a producer/authoring-door defect in packages/spec, independent of that card's connect-time fix. Deliberately left unlabeled for triage to grade.
What happens
MongoConfigSchema.options is the MongoClient passthrough, declared as placeholderFreeDeep(z.record(z.string(), z.unknown())). Nothing in it refuses credential material, so a mongo datasource can author its password as options.auth.password — and every existing refusal steps around it:
redactableConfigKeys('mongodb') is ['password','passwd','pwd','token','jwt','auth_token','authtoken'] — a top-level key-name list, and the value here is two levels down.
And it genuinely reaches the client: MongoDBDriver spreads config.options into MongoClientOptions, so auth resolves into MongoClient's credentials. That is measured in passing by #8696's new pin (bound-secret-dsn-branches.test.ts), which asserts a bound external.credentialsRefoutranks a passthrough auth block — before that change the passthrough's password was what the client used.
Why it matters
This is the at-rest half, not a connect-time bug: the value is written into sys_metadata in cleartext by an authoring path the platform accepts without comment, and handed back unredacted to anything reading the datasource record. #8082's ruling chose to refuse rather than accept residual risk for precisely this shape, and #8337 extended that to the query-string spelling on the same grounds.
⚠️ Note for whoever takes it: a refusal must not break the legitimate contents of this passthrough (replicaSet, tls, timeouts). And auth.username is not credential material — #8876's accessor documents the same asymmetry for userinfo, where only a non-empty password is treated as a secret.
Where the fix lands
packages/spec/src/data/driver/mongo.zod.ts (+ common.zod.ts if the rule is shared), and the redaction table if route 2 is taken as well. Backlink: #8696.
Found while implementing #8696's mongodb arm (the DSN-branch secret injection), and filed rather than fixed there: it is a producer/authoring-door defect in
packages/spec, independent of that card's connect-time fix. Deliberately left unlabeled for triage to grade.What happens
MongoConfigSchema.optionsis the MongoClient passthrough, declared asplaceholderFreeDeep(z.record(z.string(), z.unknown())). Nothing in it refuses credential material, so a mongo datasource can author its password asoptions.auth.password— and every existing refusal steps around it:sys_metadata.metadatais a general cleartext sink: any authored artefact whose schema permits an inline credential lands it there (datasourceconfig.password, connectorauthentication) #7990 refuses the top-levelpasswordkey (refusedInlineCredentialKey);user:password@hostin driverconfig.url) remain a live cleartext door after #7990 — refuse at publish, or accept as residual risk? #8082 refuses auser:password@userinfo insideconfig.url(credentialFreeUrl);?authToken=in an authoredconfig.url/config.syncUrlquery string is credential material the #8082 userinfo refusal does not cover #8337 refuses credential-bearing URL query parameters (CREDENTIAL_URL_QUERY_PARAMS).options.authis the same secret one syntax over from all three, exactly as #8337 was one syntax over from #8082.Measured on
origin/main@792524c22Authoring — accepted clean, no issues:
Read path — not redacted, so the cleartext comes back out of the admin API as well as sitting in
sys_metadata:redactableConfigKeys('mongodb')is['password','passwd','pwd','token','jwt','auth_token','authtoken']— a top-level key-name list, and the value here is two levels down.And it genuinely reaches the client:
MongoDBDriverspreadsconfig.optionsintoMongoClientOptions, soauthresolves intoMongoClient'scredentials. That is measured in passing by #8696's new pin (bound-secret-dsn-branches.test.ts), which asserts a boundexternal.credentialsRefoutranks a passthroughauthblock — before that change the passthrough's password was what the client used.Why it matters
This is the at-rest half, not a connect-time bug: the value is written into
sys_metadatain cleartext by an authoring path the platform accepts without comment, and handed back unredacted to anything reading the datasource record. #8082's ruling chose to refuse rather than accept residual risk for precisely this shape, and #8337 extended that to the query-string spelling on the same grounds.What a fix has to decide
user:password@hostin driverconfig.url) remain a live cleartext door after #7990 — refuse at publish, or accept as residual risk? #8082/turso:?authToken=in an authoredconfig.url/config.syncUrlquery string is credential material the #8082 userinfo refusal does not cover #8337 direction): asuperRefineonoptionsrejecting credential-bearing paths — at minimumauth.password, with a message pointing atexternal.credentialsRef/ the connection form's secret field, the same remedy the other three refusals name. Needs a decision on how deep the refusal walks and whether it is mongo-only or a shared rule for every driver's passthrough block (postgres/mysqloptions-equivalents should be checked — this issue measured only mongo).user:password@hostin driverconfig.url) remain a live cleartext door after #7990 — refuse at publish, or accept as residual risk? #8082 declined.replicaSet,tls, timeouts). Andauth.usernameis not credential material — #8876's accessor documents the same asymmetry for userinfo, where only a non-empty password is treated as a secret.Where the fix lands
packages/spec/src/data/driver/mongo.zod.ts(+common.zod.tsif the rule is shared), and the redaction table if route 2 is taken as well. Backlink: #8696.