Context
Bugbot flagged on PR #52 (comment 3104931747).
Problem
apps/desktop/src/pages/Settings.tsx renders cloudPicture directly as an <img src={...}>. The URL comes from the Google ID token's picture claim, which we decode client-side without signature verification. If a malicious calimero:// deep link slipped through all our other validation, a crafted JWT could point picture at an attacker-controlled host — the <img> request would fire and leak the user's IP / time-of-use.
CSRF state on the OAuth flow and server-side token validation make this hard to reach in practice. This is defense-in-depth.
Scope
Two options:
- Allow-list: check the URL origin against known Google avatar hosts (
*.googleusercontent.com, lh3.googleusercontent.com, etc.) and refuse to render if it doesn't match. Fall back to a generated initials avatar.
- Proxy through backend: never render the URL directly; fetch it via
proxy_http_request (for cache / CSP purposes). Heavier.
Start with the allow-list approach. Ten lines of code in a small isTrustedAvatarHost util.
Priority
Low. User-impact is minimal; attacker needs to have already compromised the OAuth/deep-link path. Worth landing in a general hardening pass rather than a dedicated PR.
Context
Bugbot flagged on PR #52 (comment 3104931747).
Problem
apps/desktop/src/pages/Settings.tsxrenderscloudPicturedirectly as an<img src={...}>. The URL comes from the Google ID token'spictureclaim, which we decode client-side without signature verification. If a maliciouscalimero://deep link slipped through all our other validation, a crafted JWT could pointpictureat an attacker-controlled host — the<img>request would fire and leak the user's IP / time-of-use.CSRF state on the OAuth flow and server-side token validation make this hard to reach in practice. This is defense-in-depth.
Scope
Two options:
*.googleusercontent.com,lh3.googleusercontent.com, etc.) and refuse to render if it doesn't match. Fall back to a generated initials avatar.proxy_http_request(for cache / CSP purposes). Heavier.Start with the allow-list approach. Ten lines of code in a small
isTrustedAvatarHostutil.Priority
Low. User-impact is minimal; attacker needs to have already compromised the OAuth/deep-link path. Worth landing in a general hardening pass rather than a dedicated PR.