Desktop Authentication Service Takeover via Unrestricted Plugin Capability Inheritance
How a logic discrepancy between a command-line plugin validator and an in-process QML runtime allowed untrusted third-party desktop plugins to inherit privileged authentication capabilities and hijack the lock screen.
The target
Modern desktop environments often provide plugin systems that allow developers to customize shell widgets, lock screens, and system trays. In a public open-source desktop shell, developers introduced an explicit security boundary to isolate authentication prompts: sensitive capabilities like ["authentication"] were strictly limited to verified first-party services (such as polkit and lock), managed by a central AuthServiceStore.
Plugins installed by users run with low privileges and are subject to validation by an official CLI tool prior to installation.
The vulnerability
When examining the codebase, a subtle discrepancy was discovered between what the CLI validator enforces versus what the runtime actually consumes:
- The Hardening Rule: The CLI validator checks plugin metadata against an explicit list of prohibited capabilities to prevent third-party plugins from requesting authentication privileges directly.
- The Inheritance Loophole: The architecture supports a
clonedFromdirective in the plugin manifest, originally designed to let fork maintainers base custom plugins on standard templates:
{
"id": "custom-helper",
"name": "Custom Helper",
"omarchy": {
"clonedFrom": "omarchy.polkit"
}
}
- The Runtime Discrepancy: While the validator only checks top-level declared capabilities,
AuthServiceStore.jsin the runtime resolves capabilities by checking the plugin's ancestry: if a plugin declaresclonedFrom: "omarchy.polkit", the runtime automatically assigns it the full privilegedauthenticationcapability set without verifying cryptographic signatures or namespace ownership.
Empirical verification
To confirm the attack chain end to end:
- Validation Pre-Flight: A minimal plugin manifest was crafted containing the
clonedFromattribute pointing to the coreomarchy.polkitidentifier. The official validator CLI was executed:
$ omarchy-plugin-validate ./test-plugin
Validation successful. Plugin manifest is well-formed.
$ echo $?
0
- Runtime Execution: The plugin was placed in the local plugin directory and loaded into the desktop shell. Upon execution, the custom plugin successfully registered itself as the active
AuthServiceinstance inAuthServiceStore, replacing the default system PAM/Polkit authentication handler. - Exploitation Impact: When an administrative task (such as
sudoor package management) triggered a privilege escalation dialog, the user's password input was routed directly to the third-party plugin's callback rather than the verified system polkit agent, allowing plain-text credential capture.
Remediation
The fix requires aligning the validation logic with the runtime capability store:
- Enforce that privileged capabilities (
authentication,session-control) can only be granted to plugins whose IDs match a hardcoded, cryptographically verified first-party allowlist. - Strip or neutralize privileged attributes inherited through
clonedFromwhenever the plugin origin is external. - Unify the validation rules into a single shared parser used by both the CLI tool and the desktop runtime.
The finding was submitted with a runnable demonstration plugin and patch recommendations.