fix(security): gate plugin hook registration on granted permissions
`info.hooks` is self-reported by the sandboxed bundle, and the loader registered any recognised hook name without checking permissions. An untrusted, null-origin plugin could therefore claim `onRenderEmailBody` and replace the rendered body of any opened email without ever holding `email:render-takeover` — the permission was enforced only by the one-time consent dialog, i.e. it gated what the user was *asked*, not what the host *allowed*. Add HOOK_PERMISSIONS covering the hooks that can read message content, alter outgoing mail, or observe key state: render takeover, the three send-interception hooks, bulk-content hooks, attachment upload, and the four S/MIME hooks. Hooks absent from the map stay unrestricted (UI observation, toasts, navigation), so ordinary plugins are unaffected. Refused hooks fail closed and log the missing permission by name — a silently inert hook is far harder to diagnose than a refused one. Export hasPermission() from host-api rather than reimplementing the rule in the loader, so the hook gate and the RPC gate cannot drift apart. Remaining ~200 hooks are tracked as B-09. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f0e63de09b
commit
ae19ad888b
@@ -99,7 +99,12 @@ const PERM_PER_METHOD: Record<string, Permission | null> = {
|
||||
'sieve.regenerate': 'filters:write',
|
||||
};
|
||||
|
||||
function hasPermission(plugin: InstalledPlugin, perm: Permission): boolean {
|
||||
/**
|
||||
* Single source of truth for "may this plugin use `perm`?". Exported so the
|
||||
* loader can gate hook registration with the same rule the RPC layer uses -
|
||||
* two copies of this logic would drift.
|
||||
*/
|
||||
export function hasPermission(plugin: InstalledPlugin, perm: Permission): boolean {
|
||||
if ((IMPLICIT_PERMISSIONS as readonly string[]).includes(perm)) return true;
|
||||
if (!plugin.permissions.includes(perm)) return false;
|
||||
// Defense-in-depth: even if the manifest declares a permission, the host
|
||||
|
||||
Reference in New Issue
Block a user