Skip to content

[Security][Medium] DOM ID clobbering, unbounded storage, API response validation, OAuth URL logging, and missing CSP #71

@numbers-official

Description

@numbers-official

Summary

Seven medium-severity security findings identified during deep audit on 2026-04-05. These cover multiple attack surfaces across content scripts, storage, API boundaries, and logging.

Findings

1. Predictable DOM Element IDs in Content Script Enable Clobbering

File: src/content/selection-overlay.ts lines 29, 44, 56

Elements are injected with well-known IDs (proofsnap-selection-overlay, proofsnap-selection-box, proofsnap-instructions). A malicious page can pre-create elements with these IDs to intercept events or manipulate cleanup logic.

Fix: Use cryptographic random suffixes: overlay.id = \proofsnap-overlay-${crypto.getRandomValues(new Uint32Array(1))[0].toString(36)}``, or use Shadow DOM isolation.

2. Unbounded Screenshot Storage in IndexedDB

Files: src/services/IndexedDBService.ts lines 95-106, src/background/service-worker.ts lines 300-317

Full base64 screenshot data URLs (multi-MB each) stored with no size limits, max count, or TTL. Failed uploads remain indefinitely. An attacker causing repeated upload failures triggers local DoS via storage exhaustion.

Fix: Implement a MAX_STORED_ASSETS limit (e.g., 50) and periodic cleanup removing failed assets older than 7 days.

3. API Responses Lack Runtime Schema Validation

Files: src/services/ApiClient.ts line 175, src/services/UploadService.ts line 330, src/services/AuthService.ts lines 52, 69, 144

All API responses are deserialized via response.json() and used directly. TypeScript generics provide no runtime protection. A MITM attacker could inject malformed responses that flow into storage, DOM, and URL construction unchecked.

Fix: Add runtime validation for critical API responses (login, upload, user profile) using manual type checks or a validation library.

4. Full OAuth Response URL Logged on Error Path

File: src/services/AuthService.ts line 126

console.error('No id_token found in response', responseUrl);

Logs the complete OAuth redirect response URL which may contain tokens, nonces, and account info.

Fix: console.error('No id_token found in Google Auth response URL') without the raw URL.

5. Unsanitized mimeType Used for Filename Extension

File: src/services/UploadService.ts line 306

const filename = `screenshot_${Date.now()}.${asset.mimeType.split('/')[1]}`;

If IndexedDB asset data is tampered, split('/')[1] could contain path traversal characters affecting server-side file handling.

Fix: Whitelist extensions: const ext = ['png','jpeg','jpg','webp'].includes(rawExt) ? rawExt : 'png'.

6. Unbounded Callback Accumulation in UploadService

File: src/services/UploadService.ts lines 158-161

onUploadComplete() adds callbacks to a Map with unique keys but never removes them. Over the service worker lifecycle, this causes memory growth and duplicate invocations.

Fix: Use a single-slot callback pattern instead of a Map.

7. No CSP for Offscreen Document and Share Page

File: manifest.template.json lines 27-29

CSP is defined only for extension_pages. The offscreen document and share page lack explicit CSP <meta> tags, reducing defense-in-depth.

Fix: Add <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self'"> to offscreen.html and share.html.


Generated by Omni AI Deep Check on 2026-04-05

Metadata

Metadata

Labels

priority:mediumMedium prioritysecuritySecurity vulnerability or concern

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions