Blog | G5 Cyber Security

CSS url() Security Risks

TL;DR

Yes, controlling the content of a CSS url() property can be exploited. Attackers can use it to load malicious resources from external sites (cross-site scripting – XSS), leak sensitive information, or perform other harmful actions. Proper sanitisation and Content Security Policy (CSP) are crucial for mitigation.

Understanding the Risk

The url() function in CSS is used to specify a resource location (image, font, stylesheet, etc.). If an attacker can control the URL provided to this function, they can potentially inject malicious code or access restricted resources. This is especially dangerous when dealing with user-supplied data.

Exploitation Scenarios

  1. Cross-Site Scripting (XSS): An attacker could inject JavaScript code into a CSS file via the url() property, which then executes in the victim’s browser.
  2. Data Exfiltration: If the URL can point to an attacker-controlled server, sensitive data from the page can be sent there. This might involve using a data URI scheme or exploiting features like image pixel tracking.
  3. Redirection/Phishing: The url() property could redirect users to malicious websites.
  4. Denial of Service (DoS): Loading extremely large resources via the URL can overwhelm the browser and cause a DoS condition.

Mitigation Steps

  1. Input Validation & Sanitisation: Always validate and sanitise any user-supplied data before using it in a CSS url() property. This includes:
    • Whitelisting allowed schemes: Only allow safe URL schemes like http://, https://, data:image/svg+xml;base64, (with careful size limits), and potentially relative paths.
    • Blacklisting dangerous characters: Remove or encode characters that could be used for malicious purposes (e.g., quotes, angle brackets, JavaScript keywords).
    • Regular expression matching: Use regular expressions to ensure the URL conforms to an expected pattern.
  2. Content Security Policy (CSP): Implement a strong CSP to restrict the sources from which resources can be loaded. This is the most effective defence against XSS attacks.
    header: Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';

    This example CSP allows resources only from the same origin (‘self’), inline scripts and styles, images from the same origin and data URIs. Adjust this policy based on your application’s needs.

  3. Subresource Integrity (SRI): Use SRI to verify that files loaded from external CDNs haven’t been tampered with.
    <link rel="stylesheet" href="https://example.com/style.css" integrity="sha384-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" crossorigin="anonymous">
  4. Avoid unsafe-inline: Minimize the use of 'unsafe-inline' for scripts and styles in your CSP, as it weakens security.
  5. Regular Security Audits: Regularly audit your code and dependencies to identify potential vulnerabilities.

Example Vulnerable Code

/* DO NOT USE - VULNERABLE */
.element {
  background-image: url("" + userInput + ""); /* User input directly in URL */
}

Example Safer Code (with validation)

const allowedSchemes = ['http://', 'https://', 'data:image/svg+xml;base64,'];

function isValidURL(url) {
  if (!url) return false;
  for (const scheme of allowedSchemes) {
    if (url.startsWith(scheme)) {
      return true;
    }
  }
  return false;
}

// ... later in your code...
if (isValidURL(userInput)) {
  document.getElementById('element').style.backgroundImage = 'url("' + userInput + '")';
} else {
  console.error('Invalid URL provided.');
}
Exit mobile version