SEC2-076: Instance address keeps a user name and password typed into it, and they reach the popup footer and the downloadable log #33
Labels
No labels
bug
documentation
enhancement
performance
security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo-chromium#33
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-10-16 in a read-only security review of
postulo-chromiumatb6c1009, checked by a second, independent pass.Severity: Low · Category: Input Validation · Reference: CWE-20 (Improper Input Validation); CWE-532 (Insertion of Sensitive Information into Log File); OWASP A04:2021 (Insecure Design)
Location:
src/lib/api.js:25-47(normaliseInstance)src/lib/api.js:50-53(originPattern)src/popup.js:162-167(the footer shows the address)src/options.js:49-64(downloadLogheads the file withsettings.instance)Issue
normaliseInstanceparses the typed address withURL, insists on https away from home, dropsthe query, the fragment and a trailing
/api/v1, and returnsurl.toString():Nothing looks at
url.usernameorurl.password. An address pasted with basic-auth credentialsin it (the form a reverse proxy's documentation often shows) is accepted and stored as the
instance. Three things then follow from the stored string rather than from its origin:
originPatternusesurl.host, so the permission prompt names the bare host, while everyrequest is built as
${instance}${API}${path};fetchrefuses a URL that carriescredentials, so each call throws before it is sent, and
stateOfFailurereads that as"unreachable". The person sees Postulo as down, with no sentence naming the cause.
settings.instanceintoserver.textContent,server.titleandserver.href(src/popup.js:164-166), so the password stands in the popup in clear.downloadLogwritespostulo: settings.instanceas the first lines of the log file(
src/options.js:60).PRIVACY.md:28-31promises that the log never holds a credential, andlog.jsrecordshostOf(url)only; the header line put in front of it does not.Impact
A person who pastes a proxy address with its credentials gets a working-looking configuration
that never connects, a popup that shows the password, and a log file ("the kind of file that
gets attached to an issue",
src/lib/log.js:6) carrying it. Limited to the person's own browserand whoever they send the log to.
Fix
Refuse credentials in the address with a translated sentence, and head the log with the host
only:
Add the key to
src/_locales/en/messages.json(the other catalogues through Weblate).src/lib/api.jsis one of the files copied into postulo-thunderbird throughshared.json, sothe fix reaches that extension on its next
shared:sync.Done when
test/api.test.mjsasserts thatnormaliseInstance("https://user:secret@postulo.example.org")throws the new refusal, and a test of the log text with the options page's header shows the host
and nothing after an
@.Related
#19 (closed) is the non-JSON-answer sentence, unrelated.