
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Sun, 05 Apr 2026 14:35:15 GMT</lastBuildDate>
        <item>
            <title><![CDATA[General availability for WAF Content Scanning for file malware protection]]></title>
            <link>https://blog.cloudflare.com/waf-content-scanning-for-malware-detection/</link>
            <pubDate>Thu, 07 Mar 2024 14:00:14 GMT</pubDate>
            <description><![CDATA[ Announcing the General Availability of WAF Content Scanning, protecting your web applications and APIs from malware by scanning files in-transit ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Kt17OxA0rO7EXenzZGJXf/b2410be6e9de67c10ee488c6c23ac60d/TXqgLUZ0L11n0fBPaEzi9DYuGJ_QGmAxLbfS9xKb6c_N9nBhFQhsQ4TsJ7kU82ADmgLjkM6EWmZXDBO_5OX4urYAeca428kjsFf2MM8RWBUsNtkg0gEO75D-brm4.png" />
            
            </figure><p>File upload is a common feature in many web applications. Applications may allow users to upload files like images of flood damage to file an insurance claim, PDFs like resumes or cover letters to apply for a job, or other documents like receipts or income statements. However, beneath the convenience lies a potential threat, since allowing unrestricted file uploads can expose the web server and your enterprise network to significant risks related to <a href="https://www.cloudflare.com/network-services/solutions/enterprise-network-security/">security</a>, privacy, and compliance.</p><p>Cloudflare recently introduced <a href="/waf-content-scanning/">WAF Content Scanning</a>, our in-line <a href="https://www.cloudflare.com/application-services/solutions/">malware file detection and prevention solution</a> to stop malicious files from reaching the web server, offering our Enterprise WAF customers an additional line of defense against security threats.</p><p>Today, we're pleased to announce that the feature is now generally available. It will be automatically rolled out to existing WAF Content Scanning customers before the end of March 2024.</p><p>In this blog post we will share more details about the new version of the feature, what we have improved, and reveal some of the technical challenges we faced while building it. This feature is available to Enterprise WAF customers as an add-on license, contact your account team to get it.</p>
    <div>
      <h2>What to expect from the new version?</h2>
      <a href="#what-to-expect-from-the-new-version">
        
      </a>
    </div>
    <p>The feedback from the early access version has resulted in additional improvements. The main one is expanding the maximum size of scanned files from 1 MB to 15 MB. This change required a complete redesign of the solution's architecture and implementation. Additionally, we are improving the dashboard visibility and the overall analytics experience.</p><p>Let's quickly review how malware scanning operates within our WAF.</p>
    <div>
      <h2>Behind the scenes</h2>
      <a href="#behind-the-scenes">
        
      </a>
    </div>
    <p>WAF Content Scanning operates in a few stages: users activate and configure it, then the scanning engine detects which requests contain files, the files are sent to the scanner returning the scan result fields, and finally users can build custom rules with these fields. We will dig deeper into each step in this section.</p>
    <div>
      <h3>Activate and configure</h3>
      <a href="#activate-and-configure">
        
      </a>
    </div>
    <p>Customers can enable the feature via the <a href="https://developers.cloudflare.com/waf/about/content-scanning/api-calls/#enable-waf-content-scanning">API</a>, or through the Settings page in the dashboard (Security → Settings) where a new section has been added for <a href="https://developers.cloudflare.com/waf/about/#detection-versus-mitigation">incoming traffic detection</a> configuration and enablement. As soon as this action is taken, the enablement action gets distributed to the Cloudflare network and begins scanning incoming traffic.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/33blcVizOJx9iZiSqAzX3Y/5bdd6e83500ebf66d842a92854515b4e/image1-27.png" />
            
            </figure><p>Customers can also add a <a href="https://developers.cloudflare.com/waf/about/content-scanning/#2-optional-configure-a-custom-scan-expression">custom configuration</a> depending on the file upload method, such as a base64 encoded file in a JSON string, which allows the specified file to be parsed and scanned automatically.</p><p>In the example below, the customer wants us to look at JSON bodies for the key “file” and scan them.</p><p>This rule is written using the <a href="https://developers.cloudflare.com/ruleset-engine/rules-language/">wirefilter syntax</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2bZfebbWfiQfchZpKJv75q/6088e2458deff944c3965647be3249ef/Scanning-all-incoming-requests-for-file-malware.png" />
            
            </figure>
    <div>
      <h3>Engine runs on traffic and scans the content</h3>
      <a href="#engine-runs-on-traffic-and-scans-the-content">
        
      </a>
    </div>
    <p>As soon as the feature is activated and configured, the scanning engine runs the pre-scanning logic, and identifies content automatically via heuristics. In this case, the engine logic does not rely on the <i>Content-Type</i> header, as it’s easy for attackers to manipulate. When relevant content or a file has been found**,** the engine connects to the <a href="https://developers.cloudflare.com/cloudflare-one/policies/gateway/http-policies/antivirus-scanning/">antivirus (AV) scanner</a> in our <a href="https://www.cloudflare.com/zero-trust/solutions/">Zero Trust solution</a> to perform a thorough analysis and return the results of the scan. The engine uses the scan results to propagate useful fields that customers can use.</p>
    <div>
      <h3>Integrate with WAF</h3>
      <a href="#integrate-with-waf">
        
      </a>
    </div>
    <p>For every request where a file is found, the scanning engine returns various <a href="https://developers.cloudflare.com/waf/about/content-scanning/#content-scanning-fields">fields</a>, including:</p>
            <pre><code>cf.waf.content_scan.has_malicious_obj,
cf.waf.content_scan.obj_sizes,
cf.waf.content_scan.obj_types, 
cf.waf.content_scan.obj_results</code></pre>
            <p>The scanning engine integrates with the WAF where customers can use those fields to <a href="https://developers.cloudflare.com/waf/custom-rules/">create custom WAF rules</a> to address various use cases. The basic use case is primarily blocking malicious files from reaching the web server. However, customers can construct more complex logic, such as enforcing constraints on parameters such as file sizes, file types, endpoints, or specific paths.</p>
    <div>
      <h2>In-line scanning limitations and file types</h2>
      <a href="#in-line-scanning-limitations-and-file-types">
        
      </a>
    </div>
    <p>One question that often comes up is about the file types we detect and scan in WAF Content Scanning. Initially, addressing this query posed a challenge since HTTP requests do not have a definition of a “file”, and scanning all incoming HTTP requests does not make sense as it adds extra processing and latency. So, we had to decide on a definition to spot HTTP requests that include files, or as we call it, “uploaded content”.</p><p>The WAF Content Scanning engine makes that decision by filtering out certain content types identified by heuristics. Any content types not included in a predefined list, such as <code>text/html</code>, <code>text/x-shellscript</code>, <code>application/json</code>, and <code>text/xml</code>, are considered uploaded content and are sent to the scanner for examination. This allows us to scan a <a href="https://crates.io/crates/infer#supported-types">wide range</a> of content types and file types without affecting the performance of all requests by adding extra processing. The wide range of files we scan includes:</p><ul><li><p>Executable (e.g., <code>.exe</code>, <code>.dll</code>, <code>.wasm</code>)</p></li><li><p>Documents (e.g., <code>.doc</code>, <code>.docx</code>, <code>.pdf</code>, <code>.ppt</code>, <code>.xls</code>)</p></li><li><p>Compressed (e.g., <code>.7z</code>, <code>.gz</code>, <code>.zip</code>, <code>.rar</code>)</p></li><li><p>Image (e.g., <code>.jpg</code>, <code>.png</code>, <code>.gif</code>, <code>.webp</code>, <code>.tif</code>)</p></li><li><p>Video and audio files within the 15 MB file size range.</p></li></ul><p>The file size scanning limit of 15 Megabytes comes from the fact that the in-line file scanning as a feature is running in real time, which offers safety to the web server and instant access to clean files, but also impacts the whole request delivery process. Therefore, it’s crucial to scan the payload without causing significant delays or interruptions; namely increased CPU time and latency.</p>
    <div>
      <h2>Scaling the scanning process to 15 MB</h2>
      <a href="#scaling-the-scanning-process-to-15-mb">
        
      </a>
    </div>
    <p>In the early design of the product, we built a system that could handle requests with a maximum body size of 1 MB, and increasing the limit to 15 MB had to happen without adding any extra latency. As mentioned, this latency is not added to all requests, but only to the requests that have uploaded content. However, increasing the size with the same design would have increased the latency by 15x for those requests.</p><p>In this section, we discuss how we previously managed scanning files embedded in JSON request bodies within the former architecture as an example, and why it was challenging to expand the file size using the same design, then compare the same example with the changes made in the new release to overcome the extra latency in details.</p>
    <div>
      <h3>Old architecture used for the Early Access release</h3>
      <a href="#old-architecture-used-for-the-early-access-release">
        
      </a>
    </div>
    <p>In order for customers to use the content scanning functionality in scanning files embedded in JSON request bodies, they had to configure a rule like:</p>
            <pre><code>lookup_json_string(http.request.body.raw, “file”)</code></pre>
            <p>This means we should look in the request body but only for the “file” key, which in the image below contains a base64 encoded string for an image.</p><p>When the request hits our Front Line (FL) NGINX proxy, we buffer the request body. This will be in an in-memory buffer, or written to a temporary file if the size of the request body exceeds the NGINX configuration of <a href="https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size">client_body_buffer_size</a>. Then, our WAF engine executes the lookup_json_string function and returns the base64 string which is the content of the file key. The base64 string gets sent via Unix Domain Sockets to our malware scanner, which does MIME type detection and returns a verdict to the file upload scanning module.</p><p>This architecture had a bottleneck that made it hard to expand on: the expensive latency fees we had to pay. The request body is first buffered in NGINX and then copied into our WAF engine, where rules are executed. The malware scanner will then receive the execution result — which, in the worst scenario, is the entire request body — over a Unix domain socket. This indicates that once NGINX buffers the request body, we send and buffer it in two other services.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OZumKn4Bar00t8BxfPuz6/bf2ffb663817b3092dccc2acd2701374/Screenshot-2024-03-07-at-12.31.52.png" />
            
            </figure>
    <div>
      <h3>New architecture for the General Availability release</h3>
      <a href="#new-architecture-for-the-general-availability-release">
        
      </a>
    </div>
    <p>In the new design, the requirements were to scan larger files (15x larger) while not compromising on performance. To achieve this, we decided to bypass our WAF engine, which is where we introduced the most latency.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3e2jggqBgIMdZaAwQPkiq9/01f31f022d7ef735cdb536041a28f25b/Screenshot-2024-03-07-at-12.32.42.png" />
            
            </figure><p>In the new architecture, we made the malware scanner aware of what is needed to execute the rule, hence bypassing the Ruleset Engine (RE). For example, the configuration “lookup_json_string(http.request.body.raw, “file”)”, will be represented roughly as:</p>
            <pre><code>{
   Function: lookup_json_string
   Args: [“file”]
}</code></pre>
            <p>This is achieved by walking the <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> (AST) when the rule is configured, and deploying the sample struct above to our global network. The struct’s values will be read by the malware scanner, and rule execution and malware detection will happen within the same service. This means we don’t need to read the request body, execute the rule in the Ruleset Engine (RE) module, and then send the results over to the malware scanner.</p><p>The malware scanner will now read the request body from the temporary file directly, perform the rule execution, and return the verdict to the file upload scanning module.</p><p>The file upload scanning module populates these <a href="https://developers.cloudflare.com/waf/about/content-scanning/#content-scanning-fields">fields</a>, so they can be used to write custom rules and take actions. For example:</p>
            <pre><code>all(cf.waf.content_scan.obj_results[*] == "clean")</code></pre>
            <p>This module also enriches our logging pipelines with these fields, which can then be read in <a href="https://developers.cloudflare.com/logs/about/">Log Push</a>, <a href="https://developers.cloudflare.com/logs/edge-log-delivery/">Edge Log Delivery</a>, Security Analytics, and Firewall Events in the dashboard. For example, this is the security log in the Cloudflare dashboard (Security → Analytics) for a web request that triggered WAF Content Scanning:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2XGS4YhMjcm2rLRg9znwVr/9f1e5dcd67808f3bba13b80296a1aa42/image5-15.png" />
            
            </figure>
    <div>
      <h2>WAF content scanning detection visibility</h2>
      <a href="#waf-content-scanning-detection-visibility">
        
      </a>
    </div>
    <p>Using the concept of incoming traffic detection, WAF Content Scanning enables users to identify hidden risks through their traffic signals in the analytics before blocking or mitigating matching requests. This reduces false positives and permits security teams to make decisions based on well-informed data. Actually, this isn't the only instance in which we apply this idea, as we also do it for a number of other products, like WAF Attack Score and Bot Management.</p><p>We have integrated helpful information into our security products, like Security Analytics, to provide this data visibility. The <b>Content Scanning</b> tab, located on the right sidebar, displays traffic patterns even if there were no WAF rules in place. The same data is also reflected in the sampled requests, and you can create new rules from the same view.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6M1QR4dFLFsv0sG8xQ7ezj/83ec1b533b3b2c490451d6624685a26b/image7-4.png" />
            
            </figure><p>On the other hand, if you want to fine-tune your security settings, you will see better visibility in Security Events, where these are the requests that match specific rules you have created in WAF.</p><p>Last but not least, in our <a href="https://developers.cloudflare.com/logs/reference/log-fields/zone/http_requests/">Logpush</a> datastream, we have included the scan fields that can be selected to send to any external log handler.</p>
    <div>
      <h2>What’s next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>Before the end of March 2024, all current and new customers who have enabled WAF Content Scanning will be able to scan uploaded files up to 15 MB. Next, we'll focus on improving how we handle files in the rules, including adding a dynamic header functionality. Quarantining files is also another important feature we will be adding in the future. If you're an Enterprise customer, reach out to your account team for more information and to get access.</p> ]]></content:encoded>
            <category><![CDATA[Security Week]]></category>
            <category><![CDATA[WAF]]></category>
            <category><![CDATA[WAF Rules]]></category>
            <category><![CDATA[Content Scanning]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[General Availability]]></category>
            <category><![CDATA[Anti Malware]]></category>
            <guid isPermaLink="false">018GZnJIhpYLWge6uKNfnd</guid>
            <dc:creator>Radwa Radwan</dc:creator>
            <dc:creator>Paschal Obba</dc:creator>
            <dc:creator>Shreya Shetty</dc:creator>
        </item>
    </channel>
</rss>