Skip to content

[Security][Medium] OAuth token logging, missing rate limiting, offscreen sender validation, and hardcoded logging config #67

@numbers-official

Description

@numbers-official

Overview

Deep audit (2026-03-27) identified 6 new medium-severity security findings not covered by existing issues.


Finding 1: Google OAuth Response URL Logged with Tokens on Failure

File: src/services/AuthService.ts, line 126

When Google OAuth fails to return an id_token, the entire responseUrl is logged:

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

This URL may contain access_token, state, and other sensitive OAuth parameters. Distinct from #47/#20 which cover other logging issues.

Fix: Log only the error condition: console.error('No id_token found in Google auth response');


Finding 2: No Client-Side Rate Limiting on Login/Signup

File: src/popup/AuthForm.tsx, lines 21-41

handleSubmit sends login/signup requests with no attempt counting, throttling, or backoff. Enables automated brute-force against the API.

Fix: Implement attempt counter with exponential backoff (3 failures -> 5s wait, 5 failures -> 30s lockout).


Finding 3: Content Script innerHTML with DOM Clobbering Risk

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

Content script injects UI into host page DOM via innerHTML. Elements appended to document.body are accessible to host page JS, enabling DOM clobbering and future XSS regression if dynamic data is interpolated.

Fix: Use Shadow DOM for content script UI elements; replace innerHTML with createElement/textContent.


Finding 4: enableLogging: true Hardcoded with No Production Controls

File: src/config/environment.ts, line 15

export const config: EnvironmentConfig = {
  apiUrl: 'https://api.numbersprotocol.io/api/v3',
  enableLogging: true,  // Always on, no build-time or runtime toggle
  timeout: 60000,
};

The codebase has ~80+ console.log calls that are always active. No mechanism exists to suppress logging in production. This is the architectural gap beyond #20's specific verbose-log instances.

Fix: Use Vite's define to strip logging in production builds. Replace direct console.log with a logging utility respecting the config flag.


Finding 5: Offscreen Document Message Handler Lacks Sender Validation

File: src/offscreen/offscreen.ts, lines 29-48

The offscreen onMessage handler processes ADD_WATERMARK, CROP_IMAGE, and GET_GEOLOCATION without validating sender. Distinct from #19 which covers the service worker handler.

chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
  if (message.type === 'ADD_WATERMARK') { ... }
});

Fix: Validate sender.id === chrome.runtime.id before processing.


Finding 6: No Size Validation on Screenshot Data URLs

Files: src/background/service-worker.ts, lines 428-434; src/services/UploadService.ts, lines 441-443

Screenshot data URLs (10-50+ MB on hi-DPI) pass through capture -> fetch -> ImageBitmap -> message passing -> IndexedDB -> upload with zero size validation. Can cause OOM crashes and storage exhaustion.

Fix: Add max data URL size check (e.g., 25MB) immediately after captureVisibleTab. Add try-catch around createImageBitmap chain.


Generated by Heart Beat with Omni

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