SEC2-085: The extension asks for a captures token, while the threat model's mail-client row promises listings:bind and nothing else #14
Labels
No labels
bug
documentation
enhancement
security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo-thunderbird#14
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-thunderbirdat4a10c95, checked by a second, independent pass.Severity: Informational · Category: Authentication/Authorization · Reference: CWE-250 (Execution with Unnecessary Privileges); OWASP A04:2021 (Insecure Design)
Location:
src/options.js:60-64src/options.html:17-20src/_locales/en/messages.json:10-21(tokenHint),:127-130(lacksCaptures)README.md("Try it": "tick onlycaptures")docs/THREAT-MODEL.md:21(the row "Someone with the token of a mail client")Issue
The core's threat model bounds a mail client's token tightly:
The Thunderbird extension, which is that mail client, instructs the person to make a token with
the
capturesscope "and nothing more" (options.html:17-20,tokenHint, README), and Testjudges the token by that scope alone:
Nothing in the extension mentions
listings:bind. The open feature issue #9 ("File the messageon screen into a listing's history") records the decision "One token or two. Recommended: one
token holding both scopes, since it is one extension on one profile." If that recommendation
lands, the token a Thunderbird profile holds will carry
capturesandlistings:bindtogether,and the row's "and nothing else" and its worst case ("add entries the person will read") will no
longer describe it: the same token also fills the review queue and, where pages are kept, sends
renderings (the browser-extension row's consequences). Today no call of either scope is made, so
no promise is broken yet; the two documents already point different ways, and #9 is about to pick
one.
Impact
None today. Once #1 and #9 land under one token, a token read out of a Thunderbird profile
(which is stored unencrypted, see the issue on
storage.local) reaches both the capture API andthe listings history, more than the threat model tells an operator to expect from a mail
client's token.
Fix
Decide before #9 lands, and make the documents agree:
captures, onelistings:bind), each named for its use, with Test reporting on each;docs/THREAT-MODEL.mdto say that the Thunderbird extension's token holds
capturesandlistings:bind, with theunion of the two rows' worst cases, and change
tokenHint,lacksCapturesand the README toname both scopes.
Done when
THREAT-MODEL.md's mail-client row and the extension'stokenHint/README name the samescope set, and
test/i18n.test.mjs's "the scope keeps its name" test covers every scope named.Related
#9 (open) is the feature and lists "one token or two" as a decision to take; it does not record
that one token holding both scopes contradicts the core's threat-model row, nor that the current
hint and README name only
captures. #1 (open) is the capture feature, which will usecaptures.