Skip to main content

Overview

This vulnerability occurs when an application downloads or includes code from an external source (like a CDN, third-party repository, or update server) without verifying its integrity. If the external source is compromised, or if an attacker can perform a Man-in-the-Middle (MitM) attack, they can substitute the legitimate code with a malicious version. The application, trusting the source, then executes the malicious code, leading to attacks like Cross-Site Scripting (XSS), data theft, or complete system compromise. 🌐📥➡️😈

Business Impact

Failure to check code integrity can lead to severe supply chain attacks:
  • Client-Side Attacks (XSS): If a CDN-hosted JavaScript library is compromised, the attacker’s script runs on every user’s browser, potentially stealing credentials, session cookies, or PII.
  • Server-Side Attacks (RCE): If a server-side auto-update mechanism or remote file include downloads and executes malicious code, the attacker can gain full control of the server.
  • Loss of Trust: Users and customers trust that the application’s code is legitimate. A breach originating from a compromised dependency erodes this trust.

Reference Details

CWE ID: CWE-494 Related CWEs: CWE-829 (Untrusted Control Sphere), CWE-345 (Data Authenticity) OWASP Top 10 (2021): A08:2021 - Software and Data Integrity Failures Severity: High to Critical

Framework-Specific Analysis and Remediation

This vulnerability manifests in two primary ways:
  1. Client-Side (Frontend): Including scripts or stylesheets from CDNs without using Subresource Integrity (SRI).
  2. Server-Side (Backend): Implementing insecure auto-update features, or dynamically include/require-ing code from remote URLs (e.g., common in PHP).
Remediation:
  • Client-Side: Always use the integrity attribute (with a SHA hash) in <script> and <link> tags when loading resources from external CDNs.
  • Server-Side: Do not include/execute code from remote URLs. If auto-updates are necessary, download packages over HTTPS, verify their digital signatures (e.g., GPG, RSA) against a trusted public key, and check file hashes against a secure manifest.

Framework Context

This is less common in Python frameworks themselves but can occur in deployment scripts or custom application logic that fetches resources. The primary risk is often client-side (in Django/Flask templates).

Vulnerable Scenario 1: Missing Subresource Integrity (SRI) in Template

<html>
<head>
  <script src="[https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js](https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js)"></script>
</head>
<body>
  ...
</body>
</html>

Vulnerable Scenario 2: Insecure Server-Side Update Check

A custom admin utility to “check for updates” downloads and runs a script.
# utils/updater.py
import requests
import os

def check_for_updates():
    try:
        # DANGEROUS: Downloading script over HTTP (vulnerable to MitM).
        response = requests.get("[http://updates.example-utility.com/latest.py](http://updates.example-utility.com/latest.py)")
        if response.status_code == 200:
            script_content = response.text
            # DANGEROUS: Executing code downloaded without signature/hash validation.
            exec(script_content)
    except requests.RequestException as e:
        print(f"Failed to check for updates: {e}")

Mitigation and Best Practices

  • Templates: Add the integrity and crossorigin attributes to all <script> and <link rel="stylesheet"> tags loading from external CDNs.
  • Server-Side: Download updates over HTTPS. Validate signatures using a trusted public key (e.g., using gnupg or cryptography libraries) and check SHA hashes against a manifest file (also downloaded securely). Do not use exec() on untrusted code.

Secure Code Example

<html>
<head>
  <script
    src="[https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js](https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js)"
    integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
    crossorigin="anonymous"
  ></script>
</head>
<body>
  ...
</body>
</html>
# utils/updater_secure.py (Secure Update Concept)
import requests
import hashlib
# Assume 'verify_signature' function exists using a trusted public key
# from cryptography.hazmat.primitives.asymmetric import padding
# from cryptography.hazmat.primitives import hashes

def check_for_updates_secure():
    try:
        # SECURE: Download over HTTPS
        package_url = "[https://updates.example-utility.com/latest.pkg](https://updates.example-utility.com/latest.pkg)"
        manifest_url = "[https://updates.example-utility.com/latest.manifest](https://updates.example-utility.com/latest.manifest)"

        pkg_response = requests.get(package_url, verify=True) # verify=True is default
        manifest_response = requests.get(manifest_url, verify=True)
        pkg_response.raise_for_status()
        manifest_response.raise_for_status()

        package_bytes = pkg_response.content
        manifest = manifest_response.json() # Assume manifest is JSON

        # SECURE: 1. Verify manifest signature (if manifest is signed)
        # if not verify_signature(manifest['signature'], manifest['payload'], trusted_pub_key):
        #    raise Exception("Invalid manifest signature!")

        # SECURE: 2. Verify package hash against manifest
        expected_hash = manifest['package_hash_sha256']
        actual_hash = hashlib.sha256(package_bytes).hexdigest()
        if actual_hash != expected_hash:
             raise Exception("Package hash mismatch!")

        # SECURE: 3. Install/process the verified package (do not use exec!)
        # (e.g., unpack to specific directory, update DB)
        # install_package(package_bytes) # Assume this exists and is safe

    except Exception as e:
        print(f"Secure update failed: {e}")

Testing Strategy

Scan HTML templates for <script src="..."> and <link rel="stylesheet" href="..."> tags loading from external domains. Ensure they have integrity and crossorigin attributes. Review server-side code for file downloads (requests.get, urllib.request) followed by execution (exec, os.system, subprocess) or loading (pickle.load). Verify signatures and hash checks are performed on downloaded code/packages.