super-productivity/electron/shared-with-frontend/local-rest-api.model.ts
Johannes Millan 4b0550be35
fix(security): harden Local REST API against DNS rebinding and field injection (#6996)
* fix(security): harden Local REST API against DNS rebinding and field injection

- Add Host header validation to block DNS rebinding attacks from
  malicious websites targeting the localhost API
- Add IS_ELECTRON guard in handler init() for defense-in-depth
- Add allowlist of task fields settable via API (title, notes, isDone,
  timeEstimate, timeSpent, projectId, tagIds, dueDay, dueWithTime,
  plannedAt) to prevent state corruption via injected internal fields
- Validate source query parameter instead of blind cast
- Add tests verifying disallowed fields are stripped from POST and PATCH

https://claude.ai/code/session_01YJNc4gUCkHHrAAhXJBEaop

* fix: address review findings from daily code review

Security hardening:
- Block cloud metadata endpoints (169.254.169.254, metadata.google.internal)
  even when allowPrivateNetwork is true (SSRF protection)
- Add HTTP method allowlist to PluginHttp request() to prevent abuse
- Add rate limiting (max 50 concurrent) to Local REST API

Bug fixes:
- Fix hardcoded 'ICAL' issueProviderKey in calendar effects; use event's
  actual provider key with ICAL fallback
- Fix race condition in TimeBlockDeleteSidecarService: push IDs instead
  of replacing to prevent data loss on rapid bulk deletes
- Backfill missing issueProviderKey on cached calendar events from
  localStorage (backward compatibility)
- Fix btoa(String.fromCharCode(...spread)) overflow for long strings
  by using loop-based approach

Minor:
- Cap HiddenCalendarEventsService to 500 entries max (prevent
  unbounded localStorage growth)
- Fix misleading "deep clone" comment to "shallow clone"

https://claude.ai/code/session_01YJNc4gUCkHHrAAhXJBEaop

* test: fix unit test failures from review hardening changes

- Replace IS_ELECTRON guard with window.ea?.onLocalRestApiRequest check
  in handler init() so tests can mock the API without navigator.userAgent
- Update plugin-http spec to expect "cloud metadata endpoints" error
  message (was "private/local") for 169.254.169.254 and metadata.google
- Fix allowlist test expectation: title is an allowed field and passes
  through pickAllowedFields as expected

https://claude.ai/code/session_01YJNc4gUCkHHrAAhXJBEaop

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-29 11:59:27 +02:00

33 lines
775 B
TypeScript

export const LOCAL_REST_API_HOST = '127.0.0.1';
export const LOCAL_REST_API_PORT = 3876;
export const LOCAL_REST_API_TIMEOUT_MS = 15000;
export const LOCAL_REST_API_MAX_BODY_BYTES = 1024 * 1024;
export const LOCAL_REST_API_MAX_CONCURRENT_REQUESTS = 50;
export interface LocalRestApiRequestPayload {
requestId: string;
method: string;
path: string;
query: Record<string, string | string[]>;
body?: unknown;
}
export interface LocalRestApiSuccessBody {
ok: true;
data: unknown;
}
export interface LocalRestApiErrorBody {
ok: false;
error: {
code: string;
message: string;
details?: unknown;
};
}
export interface LocalRestApiResponsePayload {
requestId: string;
status: number;
body: LocalRestApiSuccessBody | LocalRestApiErrorBody;
}