Skip to content

[Security][High] SafeResourceUrlPipe bypasses Angular XSS protection without URL validation #3382

Description

@numbers-official

Summary

The SafeResourceUrlPipe at src/app/shared/pipes/safe-resource-url/safe-resource-url.pipe.ts blindly calls bypassSecurityTrustResourceUrl() on any URL input without validation, effectively disabling Angular's built-in XSS protection for all iframe sources.

Affected Files

  • src/app/shared/pipes/safe-resource-url/safe-resource-url.pipe.ts (lines 10-11) — pipe accepts any and trusts it unconditionally
  • src/app/features/wallets/wallets.page.html:20 — used with safeResourceUrl pipe
  • src/app/features/data-policy/data-policy.page.html:13
  • src/app/features/home/activities/network-action-order-details/network-action-order-details.page.html:11
  • src/app/features/terms-of-use/terms-of-use.page.html:13

Additionally, 7 other components call bypassSecurityTrustResourceUrl() directly (e.g., capture-details-with-iframe.component.ts:127, details.page.ts:286, edit-caption.page.ts:46, collection-tab.component.ts:25, app.component.ts:127,151).

Impact

  • If any upstream data source is compromised or if user-controllable data flows into URL construction, an attacker could inject a javascript: or data: URI to achieve cross-site scripting (XSS) within the app WebView.
  • The pipe's any type parameter eliminates TypeScript's type safety, allowing non-string values to pass through without compile-time checks.

Suggested Fix

  1. Add an allowlist of trusted URL prefixes (e.g., the configured BUBBLE_IFRAME_URL domain) to SafeResourceUrlPipe.
  2. Validate that the URL matches the allowlist before calling bypassSecurityTrustResourceUrl().
  3. Change the pipe's input type from any to string.
  4. Consider centralizing all bypassSecurityTrust* calls into a single service with URL validation.
transform(url: string): SafeResourceUrl {
  const trustedPrefixes = [BUBBLE_IFRAME_URL, 'https://trusted-domain.com'];
  if (!trustedPrefixes.some(prefix => url.startsWith(prefix))) {
    console.warn('Untrusted URL blocked:', url);
    return '';
  }
  return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}

Generated by Health Monitor with Omni

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

priority:highHigh prioritysecurityPull requests that address a security vulnerability

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions