Mask the SMTP username, and name public tokens PUBLIC - #156
Merged
Merged
Conversation
EMAIL_HOST_USER was a plain str, so the startup "Settings from env" dump
and `plain settings list` printed it in full. With Postmark, Mailgun, and
SES the SMTP username is the API token itself, so that leaks a live
credential into production logs. Secret[T] is an annotation marker only --
the runtime value and the SMTP backend are unchanged.
Rename CONNECT_PAGEVIEWS_TOKEN to CONNECT_PAGEVIEWS_PUBLIC_TOKEN. It is
genuinely public (the {% connect_pageviews %} tag renders it into page
HTML), so masking it would be false security; saying PUBLIC in the name
makes that visible at a glance instead.
Add a contract test pinning the convention: a setting whose last name
segment is TOKEN/KEY/SECRET/PASSWORD/USER is either Secret[...] or says
PUBLIC in its name. It checks both the live settings registry and every
package's default_settings.py on disk, so a package the test app does not
install is still covered.
Contributor
|
Next steps:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plain masks a setting only when its annotation is
Secret[...].EMAIL_HOST_PASSWORDwas;EMAIL_HOST_USERwasn't. With Postmark, Mailgun and SES the SMTP username is the API token, so the startup "Settings from env" dump printed a live credential into a production log. Found tonight while upgrading an app.EMAIL_HOST_USER: Secret[str].Secretis annotation-only, so the SMTP backend still receives the real value; only the display changes.CONNECT_PAGEVIEWS_TOKEN→CONNECT_PAGEVIEWS_PUBLIC_TOKEN(envPLAIN_CONNECT_PAGEVIEWS_PUBLIC_TOKEN), still a plainstr. It is a public endpoint token that{% connect_pageviews %}renders into every page's HTML, so masking it would be false security. The name now says that.TOKEN/KEY/SECRET/PASSWORD/USER/USERNAME/DSN/CREDENTIALis eitherSecret[...]or carriesPUBLICin its name. Last segment, because the trailing noun is what says what a value is, which is whyAUTH_USER_SESSION_HASH_FIELD,PASSWORD_HASHERS,OAUTH_SERVER_ACCESS_TOKEN_EXPIRYandEMAIL_SSL_KEYFILEneed no exception. There is no allowlist: the escape hatch is spelled in the setting's own name.The test AST-parses every
default_settings.pyoff disk as well as walking the registered settings, because the test app installs only one package and would never have seenEMAIL_HOST_USER. Reverting the annotation makes it fail with the file and line.Audited all 126 settings across 18 modules by what the value is and who reads it. Everything else that carries a credential was already
Secret, includingPOSTGRES_URLandPOSTGRES_MANAGEMENT_URL, which are documented withuser:password@. No other leak.Two things found and deliberately not changed:
plain settings get <NAME>prints the raw value with no masking, which is arguably an explicit reveal but is one command from a CI log; and if a future URL setting can carry a password, redacting userinfo insidedisplay_value()would read better than masking the whole URL, but it would change rendering for every URL-valued setting.Not in this repo:
dropseed/plain-publicdocuments the old setting name inapp/templates/apps/connect.html.Verified:
./scripts/fixclean; plain 839 passed, plain-email 13, plain-connect 25;./scripts/type-check plainand./scripts/type-validateclean.