<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>APEXlang Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/apexlang/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/apexlang/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Mon, 24 Aug 2026 05:38:18 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>APEXlang Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/apexlang/</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
<atom:link rel="hub" href="https://websubhub.com/hub"/>
<atom:link rel="self" href="https://www.salvis.com/blog/tag/apexlang/feed/"/>
	<item>
		<title>The Checkbox That Disables TLS</title>
		<link>https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/</link>
					<comments>https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/#respond</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sun, 23 Aug 2026 21:20:28 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[APEXlang]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=23591</guid>

					<description><![CDATA[<p>Introduction The dbLinter clients include a new setting named Allow Insecure TLS. It is disabled by default. As a result, all REST API calls verify the TLS certificate and hostname. The setting allows dbLinter to work in organisations that inspect TLS traffic using tools such as Zscaler. In larger organisations, arranging an<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/">The Checkbox That Disables TLS</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">The dbLinter clients include a new setting named <code>Allow Insecure TLS</code>. It is disabled by default. As a result, all REST API calls verify the TLS certificate and hostname. </p>



<p class="wp-block-paragraph">The setting allows dbLinter to work in organisations that inspect TLS traffic using tools such as <a href="https://help.zscaler.com/zia/understanding-ssltls-inspection" target="_blank" rel="noreferrer noopener">Zscaler</a>.</p>



<p class="wp-block-paragraph">In larger organisations, arranging an inspection bypass can be cumbersome and is often too much effort for an ad-hoc trial of dbLinter. The checkbox provides a temporary workaround and should be enabled only on a trusted network.</p>



<p class="wp-block-paragraph">However, allowing insecure TLS on untrusted networks, such as open Wi-Fi without client isolation, can let an attacker redirect traffic through their own machine using techniques like <a href="https://en.wikipedia.org/wiki/ARP_spoofing" target="_blank" rel="noreferrer noopener">ARP spoofing</a>. The attacker can also operate the access point themselves, for example, by creating a rogue Wi-Fi hotspot.</p>



<p class="wp-block-paragraph">In this blog post, I demonstrate the effect of this checkbox.</p>



<h2 id="allow-insecure-tls" class="wp-block-heading">Allow Insecure TLS</h2>



<p class="wp-block-paragraph">The latest version of dbLinter for VS Code has a checkbox that disables certificate and hostname verification.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox.png"><img fetchpriority="high" decoding="async" width="1024" height="833" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-1024x833.png" alt="Allow Insecure TLS Checkbox in VS Code" class="wp-image-23595" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-1024x833.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-300x244.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-768x624.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-1536x1249.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-2048x1665.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-92x75.png 92w, https://www.salvis.com/blog/wp-content/uploads/2026/08/allow-insecure-tls-checkbox-480x390.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">dbLinter&#8217;s <code>allowInsecureTls</code> setting is nothing unusual. Many common tools offer a similar option, including curl (<code>--insecure</code>), wget (<code>--no-check-certificate</code>), and git (<code>--config http.sslVerify false</code>).</p>



<h2 id="installing-and-configuring-a-proxy" class="wp-block-heading">Installing and Configuring a Proxy</h2>



<p class="wp-block-paragraph">I run this demo on macOS 26.6.2.</p>



<p class="wp-block-paragraph">A simple proxy is <a href="https://www.mitmproxy.org/" data-type="link" data-id="https://www.mitmproxy.org/" target="_blank" rel="noreferrer noopener">mitmweb</a>. We can install and configure it as follows:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>brew install mitmproxy
networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 8090
mitmweb --listen-port 8090 --web-port 8091 --allow-hosts '^api\.dblinter\.app'</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">brew</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">install</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">mitmproxy</span></span>
<span class="line"><span style="color: #DCDCAA">networksetup</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-setsecurewebproxy</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Wi-Fi&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">127.0</span><span style="color: #CE9178">.0.1</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8090</span></span>
<span class="line"><span style="color: #DCDCAA">mitmweb</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--listen-port</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8090</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--web-port</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8091</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--allow-hosts</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;^api\.dblinter\.app&#39;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;20:36:20.907&#93; HTTP(S) proxy listening at *:8090.
&#91;20:36:20.908&#93; Web server listening at http://127.0.0.1:8091/?token=f83b02032aaaccd282ad3925a484fcdb</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;20:36:20.907&#93; HTTP(S) proxy listening at *:8090.</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:36:20.908&#93; Web server listening at http://127.0.0.1:8091/?token=f83b02032aaaccd282ad3925a484fcdb</span></span></code></pre></div>



<p class="wp-block-paragraph">The <code>mitmweb</code> command starts the proxy and listens on port 8090 for TLS traffic between localhost and <code>api.dblinter.app</code>. All other traffic is bypassed. </p>



<p class="wp-block-paragraph">The <code>mitmweb</code> proxy also opens the following web page:</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start.png"><img decoding="async" width="1024" height="201" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-1024x201.png" alt="mitmproxy after start up" class="wp-image-23617" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-1024x201.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-300x59.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-768x150.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-150x29.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start-480x94.png 480w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-start.png 1281w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<h2 id="intercepting-traffic" class="wp-block-heading">Intercepting Traffic</h2>



<p class="wp-block-paragraph">To generate traffic, we launch VS Code and open a SQL file. This produces the following in the output panel for dbLinter:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>2026-08-23 20:37:43.216 &#91;Info &#93; Starting dbLinter Language Server.
2026-08-23 20:37:43.539 &#91;Info &#93; connect.
2026-08-23 20:37:43.611 &#91;Info &#93; initialize VSCode 1.10.0.
2026-08-23 20:37:43.646 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.
2026-08-23 20:37:43.651 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.
2026-08-23 20:37:43.671 &#91;Warn &#93; TLS certificate and hostname verification are disabled for dbLinter repository API calls. Use this temporary workaround only when TLS interception cannot be bypassed.
2026-08-23 20:37:45.533 &#91;Info &#93; Configuration dbLinter of tenant Grisselbav loaded with 294 check methods.
2026-08-23 20:37:45.534 &#91;Info &#93; didChangeConfiguration.
2026-08-23 20:37:45.703 &#91;Info &#93; tests returned 43 tests.
2026-08-23 20:37:45.796 &#91;Info &#93; parseAndCheck file:///.../dbl_client_types.sql.
2026-08-23 20:37:45.910 &#91;Info &#93; hasFeature Config returned true.
2026-08-23 20:37:46.286 &#91;Info &#93; parseAndCheck completed in 0.489 sec including 0.052 sec for checks.
2026-08-23 20:37:46.289 &#91;Info &#93; diagnostics for file:///.../dbl_client_types.sql with 2 issues.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.216 &#91;Info &#93; Starting dbLinter Language Server.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.539 &#91;Info &#93; connect.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.611 &#91;Info &#93; initialize VSCode 1.10.0.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.646 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:43.651 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">2026-08-23 20:37:43.671 &#91;Warn &#93; TLS certificate and hostname verification are disabled for dbLinter repository API calls. Use this temporary workaround only when TLS interception cannot be bypassed.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.533 &#91;Info &#93; Configuration dbLinter of tenant Grisselbav loaded with 294 check methods.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.534 &#91;Info &#93; didChangeConfiguration.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.703 &#91;Info &#93; tests returned 43 tests.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.796 &#91;Info &#93; parseAndCheck file:///.../dbl_client_types.sql.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:45.910 &#91;Info &#93; hasFeature Config returned true.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:46.286 &#91;Info &#93; parseAndCheck completed in 0.489 sec including 0.052 sec for checks.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:37:46.289 &#91;Info &#93; diagnostics for file:///.../dbl_client_types.sql with 2 issues.</span></span></code></pre></div>



<p class="wp-block-paragraph">The log contains a warning that TLS certificate and hostname verification are disabled.</p>



<p class="wp-block-paragraph">dbLinter analyses SQL and APEXlang files locally. The captured traffic lets us verify what is sent to the dbLinter API. It contains the API key and session data, but not the contents of the analysed files. The source code therefore remains within the local network.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-scaled.png"><img decoding="async" width="1024" height="538" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-1024x538.png" alt="mitmproxy request message" class="wp-image-23618" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-1024x538.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-300x158.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-768x403.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-1536x807.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-2048x1076.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-143x75.png 143w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-request-480x252.png 480w" sizes="(max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">It goes without saying that it is not good to expose the API key in plain text.</p>



<p class="wp-block-paragraph">The proxy also shows the decrypted response:</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-scaled.png"><img loading="lazy" decoding="async" width="1024" height="292" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-1024x292.png" alt="mitmproxy response message" class="wp-image-23619" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-1024x292.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-300x85.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-768x219.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-1536x438.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-2048x584.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-150x43.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/08/mitmproxy-response-480x137.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">The session object in the response contains a signature. The client can therefore detect changes to the signed content, including the validators. This prevents the proxy from silently modifying the validators or injecting malicious code. However, the signature does not prevent the proxy from reading the request and response.</p>



<h2 id="enforce-tls-verification" class="wp-block-heading">Enforce TLS Verification</h2>



<p class="wp-block-paragraph">Now let&#8217;s uncheck the <code>Allow Insecure TLS</code> checkbox and execute the <code>Reload Window</code> command. </p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2.png"><img loading="lazy" decoding="async" width="1024" height="191" src="https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-1024x191.png" alt="disallow insecure TLS in VS Code" class="wp-image-23613" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-1024x191.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-300x56.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-768x143.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-150x28.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2-480x89.png 480w, https://www.salvis.com/blog/wp-content/uploads/2026/08/image-2.png 1354w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">This produces the following in the output panel for dbLinter:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>2026-08-23 20:52:37.281 &#91;Info &#93; Starting dbLinter Language Server.
2026-08-23 20:52:37.550 &#91;Info &#93; connect.
2026-08-23 20:52:37.606 &#91;Info &#93; initialize VSCode 1.10.0.
2026-08-23 20:52:38.047 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.
2026-08-23 20:52:38.049 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.
2026-08-23 20:52:38.375 &#91;Error&#93; Failed to load configuration.

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://api.dblinter.app/api/client-session/open": (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:37.281 &#91;Info &#93; Starting dbLinter Language Server.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:37.550 &#91;Info &#93; connect.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:37.606 &#91;Info &#93; initialize VSCode 1.10.0.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:38.047 &#91;Info &#93; didOpen file:///.../dbl_client_types.sql.</span></span>
<span class="line"><span style="color: #D4D4D4">2026-08-23 20:52:38.049 &#91;Info &#93; AntlrCacheCoordinator initialized with parallel degree 1 and clearCacheThreshold 2048 of 16384 MB.</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">2026-08-23 20:52:38.375 &#91;Error&#93; Failed to load configuration.</span></span>
<span class="line"><span style="color: #D4D4D4"></span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">org.springframework.web.client.ResourceAccessException: I/O error on POST request for &quot;https://api.dblinter.app/api/client-session/open&quot;: (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target</span></span></code></pre></div>



<p class="wp-block-paragraph">The proxy presented a certificate for <code>api.dblinter.app</code> which was not issued by a trusted certification authority.</p>



<p class="wp-block-paragraph">The proxy console therefore shows the following log entry:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;20:52:38.217&#93;&#91;127.0.0.1:60439&#93; server connect api.dblinter.app:443 (91.98.90.2:443)
&#91;20:52:38.360&#93;&#91;127.0.0.1:60441&#93; client connect
&#91;20:52:38.375&#93;&#91;127.0.0.1:60439&#93; Client TLS handshake failed. The client does not trust the proxy's certificate for api.dblinter.app (OpenSSL Error(&#91;('SSL routines', '', 'ssl/tls alert certificate unknown')&#93;))
&#91;20:52:38.377&#93;&#91;127.0.0.1:60439&#93; client disconnect
&#91;20:52:38.380&#93;&#91;127.0.0.1:60439&#93; server disconnect api.dblinter.app:443 (91.98.90.2:443)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;20:52:38.217&#93;&#91;127.0.0.1:60439&#93; server connect api.dblinter.app:443 (91.98.90.2:443)</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:52:38.360&#93;&#91;127.0.0.1:60441&#93; client connect</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">&#91;20:52:38.375&#93;&#91;127.0.0.1:60439&#93; Client TLS handshake failed. The client does not trust the proxy&#39;s certificate for api.dblinter.app (OpenSSL Error(&#91;(&#39;SSL routines&#39;, &#39;&#39;, &#39;ssl/tls alert certificate unknown&#39;)&#93;))</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:52:38.377&#93;&#91;127.0.0.1:60439&#93; client disconnect</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;20:52:38.380&#93;&#91;127.0.0.1:60439&#93; server disconnect api.dblinter.app:443 (91.98.90.2:443)</span></span></code></pre></div>



<p class="wp-block-paragraph">The REST API call failed before the proxy received the HTTP request. Therefore, the API key and other request data were not exposed.</p>



<h2 id="reset-network-configuration-and-unistall-proxy" class="wp-block-heading">Reset Network Configuration and Uninstall Proxy</h2>



<p class="wp-block-paragraph">Let&#8217;s stop the proxy by pressing Ctrl-C in the terminal window running it. Then run the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>networksetup -setsecurewebproxystate "Wi-Fi" off
brew uninstall mitmproxy
rm -rf ~/.mitmproxy</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">networksetup</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-setsecurewebproxystate</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Wi-Fi&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">off</span></span>
<span class="line"><span style="color: #DCDCAA">brew</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">uninstall</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">mitmproxy</span></span>
<span class="line"><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-rf</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">~/.mitmproxy</span></span></code></pre></div>



<h2 id="conclusion" class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">The <code>Allow Insecure TLS</code> option solves a practical problem in environments where TLS inspection cannot easily be bypassed. However, it disables certificate and hostname verification. A proxy or an attacker controlling the network can then read requests, including the API key.</p>



<p class="wp-block-paragraph">The captured traffic also confirms that dbLinter analyses SQL and APEXlang files locally. Signed server responses protect the downloaded configuration from manipulation, but they do not protect confidential request data.</p>



<p class="wp-block-paragraph">Therefore, enable this option only as a temporary workaround on a trusted network. The preferred solution is to configure a TLS inspection bypass. Disable the option again as soon as possible.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/">The Checkbox That Disables TLS</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2026/08/23/the-checkbox-that-disables-tls/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Detecting Security Vulnerabilities With the APEXlang Parser</title>
		<link>https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/</link>
					<comments>https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/#respond</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Mon, 29 Jun 2026 12:12:21 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[ANTLR]]></category>
		<category><![CDATA[APEXlang]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=19914</guid>

					<description><![CDATA[<p>Introduction A parser for the APEXlang grammar enables the development of tools beyond the scope of the APEXlang compiler included in SQLcl, SQL Developer for VS Code, and ORDS. These tools can perform static code analysis, convert code, generate documentation, and visualise different aspects of an APEX application. A linter, for example,<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/">Detecting Security Vulnerabilities With the APEXlang Parser</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">A parser for the APEXlang grammar enables the development of tools beyond the scope of the APEXlang compiler included in SQLcl, SQL Developer for VS Code, and ORDS. These tools can perform static code analysis, convert code, generate documentation, and visualise different aspects of an APEX application.</p>



<p class="wp-block-paragraph">A linter, for example, can check whether an APEXlang file conforms to defined quality standards. These standards may cover project- or company-specific conventions as well as more general concerns, such as detecting potential security vulnerabilities.</p>



<p class="wp-block-paragraph">In this blog post, I explain the elements of an APEXlang file that are the basis of Grisselbav&#8217;s <a href="https://github.com/Grisselbav/APEXlang-Parser" type="link" id="https://github.com/Grisselbav/APEXlang-Parser" target="_blank" rel="noreferrer noopener">APEXlang parser</a>. Then I demonstrate how to use the parser in a simple Java program to detect a security vulnerability.</p>



<h2 id="elements-of-an-apexlang-file" class="wp-block-heading">Elements of an APEXlang File</h2>



<p class="wp-block-paragraph">An APEXlang file consists of three basic building blocks: components, properties, and groups. These elements can also be nested, as shown later.</p>



<p class="wp-block-paragraph">Here&#8217;s an excerpt of Oracle&#8217;s Universal Theme demo application.apx file:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">1) Excerpt of UT&#8217;s application.apx</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>app UT (
    name: Universal Theme 26.1 Reference
    version: 26.1.0
    group: @universal-theme
    logo {
        type: text
        text: Universal Theme
    }
    // ...removed code...
)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">app</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UT</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    name: </span><span style="color: #569CD6">Universal</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Theme</span><span style="color: #D4D4D4"> 26.1 Reference</span></span>
<span class="line"><span style="color: #D4D4D4">    version: 26.1.0</span></span>
<span class="line"><span style="color: #D4D4D4">    group: @universal-theme</span></span>
<span class="line"><span style="color: #D4D4D4">    logo {</span></span>
<span class="line"><span style="color: #D4D4D4">        type: text</span></span>
<span class="line"><span style="color: #D4D4D4">        text: </span><span style="color: #569CD6">Universal</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Theme</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// ...removed code...</span></span>
<span class="line"><span style="color: #D4D4D4">)</span></span></code></pre></div>



<h5 id="component" class="wp-block-heading">Component</h5>



<p class="wp-block-paragraph">There is one component in this example. It starts on line 1 and ends on line 10. <code>app</code> is the type of the component and <code>UT</code> the component name.</p>



<p class="wp-block-paragraph">A component body starts with a left parenthesis <code>(</code> and ends with a right parenthesis <code>)</code>.</p>



<h5 id="property" class="wp-block-heading">Property</h5>



<p class="wp-block-paragraph">In this example, we have 5 properties. The property keys are <code>name</code>, <code>version</code>, <code>group</code>, <code>type</code> and <code>text</code>. The value of a property follows a colon <code>:</code>. For <code>name</code> The value is <code>Universal Theme 26.1 Reference</code>, for <code>version</code> the value is <code>26.1.0</code> and so on.</p>



<p class="wp-block-paragraph">Please note that a property starts on a new line, and the property value starts after the colon and ends on a new line. This way, no delimiter characters are required for most property values. However, if leading or trailing spaces are significant, you have to pass the property value as a single-line string, which is enclosed in double quotes.</p>



<h5 id="group" class="wp-block-heading">Group (of properties)</h5>



<p class="wp-block-paragraph">The properties <code>type</code> and <code>text</code> are part of a group named <code>logo</code>.  The group in this example covers lines 5 to 8.</p>



<p class="wp-block-paragraph">A group body starts with an open curly bracket <code>{</code> and ends with a close curly bracket <code>}</code>.</p>



<p class="wp-block-paragraph">Properties which are not part of a group are called direct properties. This means they are defined directly in a component. Examples of direct properties are <code>name</code>, <code>version</code> and <code>group</code>.</p>



<h2 id="nesed-elements" class="wp-block-heading">Nested Elements</h2>



<p class="wp-block-paragraph">We have seen that a component may contain properties and groups. But it is also possible to nest elements.</p>



<ul class="wp-block-list">
<li>Components may contain other components besides properties and groups</li>



<li>Property values may contain groups besides simple values</li>
</ul>



<p class="wp-block-paragraph">There is no limit to the number of levels for nested elements.</p>



<p class="wp-block-paragraph">Here&#8217;s an example:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">2) Nested Component and Group</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>app UT (
    // ...removed code...
    pwaShortcut getting-started (
        name: Getting Started
        sequence: 10
        shortcut {
            target: {
                page: 500
            }
            description: Getting Started Page - Initial Page
        }
        comments {
            comments: -
        }
    )
   // ...removed code...
)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">app</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UT</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// ...removed code...</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">pwaShortcut</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">getting</span><span style="color: #D4D4D4">-started (</span></span>
<span class="line"><span style="color: #D4D4D4">        name: </span><span style="color: #569CD6">Getting</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Started</span></span>
<span class="line"><span style="color: #D4D4D4">        sequence: 10</span></span>
<span class="line"><span style="color: #D4D4D4">        shortcut {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            target: {</span></span>
<span class="line"><span style="color: #D4D4D4">                page: 500</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            description: </span><span style="color: #569CD6">Getting</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Started</span><span style="color: #D4D4D4"> Page - </span><span style="color: #569CD6">Initial</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Page</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">        comments {</span></span>
<span class="line"><span style="color: #D4D4D4">            comments: -</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    )</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #6A9955">// ...removed code...</span></span>
<span class="line"><span style="color: #D4D4D4">)</span></span></code></pre></div>



<p class="wp-block-paragraph">A nested component starts on line 3 and a nested group on line 7.</p>



<h2 id="apexlang-grammar" class="wp-block-heading">APEXlang Grammar</h2>



<figure class="wp-block-image size-medium"><a href="https://grisselbav.github.io/APEXlang-Parser/grammar.html" target="_blank" rel=" noreferrer noopener"><img loading="lazy" decoding="async" width="300" height="133" src="https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-300x133.png" alt="apxFile rule of APEXlang grammar" class="wp-image-19988" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-300x133.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-1024x453.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-768x340.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-150x66.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile-480x212.png 480w, https://www.salvis.com/blog/wp-content/uploads/2026/06/APEXlang-apxFile.png 1456w" sizes="auto, (max-width:767px) 300px, 300px" /></a></figure>



<p class="wp-block-paragraph">While the grammar documented in <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/apexlang.ebnf" target="_blank" rel="noreferrer noopener">apexlang. ebnf</a> of the <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/" target="_blank" rel="noreferrer noopener">API Reference</a> defines both the language structure and the valid APEXlang elements, the grammar used by Grisselbav&#8217;s APEXlang parser is limited to structural concerns. </p>



<p class="wp-block-paragraph">Because the parser focuses solely on syntax rather than semantic validation, the grammar remains remarkably compact.</p>



<p class="wp-block-paragraph">Click on the image above to view all the syntax diagrams. Alternatively, view the ANTLR4 source files, <a href="https://github.com/Grisselbav/APEXlang-Parser/blob/v0.2.0/src/main/antlr4/com/grisselbav/apexlang/grammar/ApexLangLexer.g4" target="_blank" rel="noreferrer noopener">ApexLangLexer.g4</a> and <a href="https://github.com/Grisselbav/APEXlang-Parser/blob/v0.2.0/src/main/antlr4/com/grisselbav/apexlang/grammar/ApexLangParser.g4" target="_blank" rel="noreferrer noopener">ApexLangParser.g4</a>, which were used to generate the parser available on <a href="https://central.sonatype.com/artifact/com.grisselbav/apexlang-parser" target="_blank" rel="noreferrer noopener">Maven Central</a>.</p>



<h2 id="apex-sert" class="wp-block-heading">APEX-SERT</h2>



<p class="wp-block-paragraph">APEX-SERT is an APEX application that scans a selected APEX application for security vulnerabilities. A vulnerability is detected by querying APEX dictionary views. All rules are defined in the <a href="https://github.com/oracle-samples/apex-sert/blob/v24.2.27.1/product/sert/sert_core/json_data/APEX-SERT%20Rules.json#L978-L1014" type="link" id="https://github.com/oracle-samples/apex-sert/blob/v24.2.27.1/product/sert/sert_core/json_data/APEX-SERT%20Rules.json#L978-L1014" target="_blank" rel="noreferrer noopener">APEX-SERT Rules.json</a> file. </p>



<p class="wp-block-paragraph">To demonstrate a practical use case, let’s look at the security check &#8220;Embed in Frames&#8221; implemented by APEX-SERT.</p>



<p class="wp-block-paragraph">When the property &#8220;Embed in Frames&#8221; is set to <code>Allow</code>, the application may be vulnerable to &#8220;clickjacking&#8221; attacks as explained in the help text of the page designer. See screenshot below.</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow.png"><img loading="lazy" decoding="async" width="1024" height="698" src="https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-1024x698.png" alt="" class="wp-image-20001" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-1024x698.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-300x205.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-768x524.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-1536x1047.png 1536w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-2048x1396.png 2048w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-110x75.png 110w, https://www.salvis.com/blog/wp-content/uploads/2026/06/embed-in-frames-allow-480x327.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">I changed the original value from <code>Allow from same origin</code> to <code>Allow</code> to simulate a security vulnerability.</p>



<p class="wp-block-paragraph">APEX-SERT runs a query similar to the following to find violations of this rule:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">3) Find Violations with SQL</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select application_id, application_name, browser_frame 
  from apex_applications
 where browser_frame not in ('Deny', 'Allow from same origin');</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> application_id, application_name, browser_frame </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> apex_applications</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> browser_frame </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> (</span><span style="color: #CE9178">&#39;Deny&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;Allow from same origin&#39;</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>APPLICATION_ID APPLICATION_NAME               BROWSER_FRAME
-------------- ------------------------------ -------------
        101252 Universal Theme 26.1 Reference Allow</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">APPLICATION_ID APPLICATION_NAME               BROWSER_FRAME</span></span>
<span class="line"><span style="color: #D4D4D4">-------------- ------------------------------ -------------</span></span>
<span class="line"><span style="color: #D4D4D4">        101252 Universal Theme 26.1 Reference Allow</span></span></code></pre></div>



<p class="wp-block-paragraph">So, the value of <code>Embed in Frames</code> is provided in the <code>browser_frame</code> column of the APEX dictionary view <code>apex_applications</code>.</p>



<p class="wp-block-paragraph">But where can we find this information in the APEXlang files?</p>



<h2 id="link-page-designer-property-to-apexlang" class="wp-block-heading">Link Page Designer Property to APEXlang</h2>



<p class="wp-block-paragraph">We find the &#8220;Embed in Frames&#8221; property in the page designer by navigating to &#8220;Shared Components&#8221; -&gt; &#8220;Application Definition&#8221; -&gt; &#8220;Security&#8221; -&gt; &#8220;Browser Security&#8221;. </p>



<p class="wp-block-paragraph">According to the <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/apexlang.ebnf" target="_blank" rel="noreferrer noopener">apexlang. ebnf</a> there is a <code>security</code> group within the <code>app</code> component. Here&#8217;s the relevant excerpt:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-start:347;--cbp-line-number-width:calc(3 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">3) Property embedInFrames within apexlang.ebnf</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;app-security> ::= &lt;indent> "security" &lt;ws> "{" &lt;line-end> { &lt;app-security-property-line> } &lt;indent> "}" &lt;line-end>
&lt;app-security-property-line> ::= &lt;indent> &lt;app-security-property> &lt;line-end>
&lt;app-security-property> ::= "deepLinking" ":" &lt;ws> ( "true" | "false" ) (* required; type: SELECT LIST *)
  | "enableDictation" ":" &lt;ws> &lt;boolean> (* required; type: YES NO *)
  | "browserCache" ":" &lt;ws> ( "true" | "false" ) (* required; type: SELECT LIST *)
  | "embedInFrames" ":" &lt;ws> ( "deny" | "allowSameOrigin" | "allow" ) (* required; type: SELECT LIST *)
  | "referrerPolicy" ":" &lt;ws> ( "noReferrer" | "noReferrerWhenDowngrade" | "origin" | "originWhenCrossOrigin" | "sameOrigin" | "strictOrigin" | "strictOriginWhenCrossOrigin" | "unsafeUrl" ) (* required; type: SELECT LIST *)
  | "htmlEscapingMode" ":" &lt;ws> ( "basic" | "extended" ) (* required; type: SELECT LIST *)
  | "httpResponseHeaders" ":" &lt;ws> &lt;multiline-string> (* type: TEXT EDITOR *)
  | "runtimeApiUsage" ":" &lt;ws> &lt;array-of-string-like-value> (* type: CHECKBOXES *)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;app-security&gt; ::= &lt;indent&gt; &quot;security&quot; &lt;ws&gt; &quot;</span><span style="color: #6A9955">{&quot; &lt;line-end&gt; { &lt;app-security-property-line&gt; }</span><span style="color: #D4D4D4"> &lt;indent&gt; &quot;}&quot; &lt;line-</span><span style="color: #569CD6">end</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;app-security-property-line&gt; ::= &lt;indent&gt; &lt;app-security-property&gt; &lt;line-</span><span style="color: #569CD6">end</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;app-security-property&gt; ::= &quot;deepLinking&quot; &quot;:&quot; &lt;ws&gt; ( &quot;</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">&quot; | &quot;</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;enableDictation&quot; &quot;:&quot; &lt;ws&gt; &lt;</span><span style="color: #569CD6">boolean</span><span style="color: #D4D4D4">&gt; </span><span style="color: #6A9955">(* required; type: YES NO *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;browserCache&quot; &quot;:&quot; &lt;ws&gt; ( &quot;</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">&quot; | &quot;</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">  | &quot;embedInFrames&quot; &quot;:&quot; &lt;ws&gt; ( &quot;deny&quot; | &quot;allowSameOrigin&quot; | &quot;allow&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;referrerPolicy&quot; &quot;:&quot; &lt;ws&gt; ( &quot;noReferrer&quot; | &quot;noReferrerWhenDowngrade&quot; | &quot;origin&quot; | &quot;originWhenCrossOrigin&quot; | &quot;sameOrigin&quot; | &quot;strictOrigin&quot; | &quot;strictOriginWhenCrossOrigin&quot; | &quot;unsafeUrl&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;htmlEscapingMode&quot; &quot;:&quot; &lt;ws&gt; ( &quot;basic&quot; | &quot;</span><span style="color: #569CD6">extended</span><span style="color: #D4D4D4">&quot; ) </span><span style="color: #6A9955">(* required; type: SELECT LIST *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;httpResponseHeaders&quot; &quot;:&quot; &lt;ws&gt; &lt;multiline-</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4">&gt; </span><span style="color: #6A9955">(* type: TEXT EDITOR *)</span></span>
<span class="line"><span style="color: #D4D4D4">  | &quot;runtimeApiUsage&quot; &quot;:&quot; &lt;ws&gt; &lt;</span><span style="color: #569CD6">array</span><span style="color: #D4D4D4">-</span><span style="color: #569CD6">of</span><span style="color: #D4D4D4">-</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4">-like-value&gt; </span><span style="color: #6A9955">(* type: CHECKBOXES *)</span></span></code></pre></div>



<p class="wp-block-paragraph">We find on line 352 the definition of the property <code>embedInFrames</code> with a list of valid values. In this case, the property key is unique. This means that no other component or group uses the property key <code>embedInFrames</code>. Therefore, we can search the folder containing the .apx files for the string <code>embedInFrames:</code> to find the position of this property. </p>



<p class="wp-block-paragraph">The matching property is located in the <span style="background-color: initial; font-family: inherit; font-size: inherit; text-align: initial;"><code>application.apx</code> file.</span></p>



<p class="wp-block-paragraph">Here&#8217;s an excerpt.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-start:46;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">4) Property embedInFrames in application.apx</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>    authorization {
        runOnPublicPages: true
    }
    security {
        deepLinking: true
        embedInFrames: allow
        runtimeApiUsage: modifyThisApp
    }
    sessionStateProtection {
        allowUrlsCreatedAfter: 1999-08-04T00:00:00
        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365
    }</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">authorization</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">runOnPublicPages</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">security</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">deepLinking</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">embedInFrames</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">allow</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">runtimeApiUsage</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">modifyThisApp</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">sessionStateProtection</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">allowUrlsCreatedAfter</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">1999-08-04T00:00:00</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">checksumSalt</span><span style="color: #D4D4D4">: 75</span><span style="color: #9CDCFE">BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span></code></pre></div>



<p class="wp-block-paragraph">Please note that properties with default values are skipped when an APEX application is exported. Therefore, we would not see the <code>embedInFrames</code> property if its value were <code>Deny</code>.</p>



<h2 id="find-vulnerability-with-apexlang-parser" class="wp-block-heading">Find Vulnerability With APEXlang Parser</h2>



<p class="wp-block-paragraph">We now have all the information we need. We can write a small demo program. This program will find this vulnerability in an APEXlang file.</p>



<p class="wp-block-paragraph">The parser exposes the parse tree through ANTLR4-generated context classes. Each parser rule becomes a context class. For example, the class <code>ApexLangParser.PropertyContext</code> represents the <a href="https://github.com/Grisselbav/APEXlang-Parser/blob/v0.2.0/src/main/antlr4/com/grisselbav/apexlang/grammar/ApexLangParser.g4#L66-L68" target="_blank" rel="noreferrer noopener">property</a> parser rule. This makes it easy to traverse the <code>ApexLangDocument</code> using Java streams.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">5) DemoFindVulnerability.java</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>//DEPS com.grisselbav:apexlang-parser:0.2.0

import com.grisselbav.apexlang.grammar.*;

class DemoFindVulnerability {
    public static void main(String[] args) {
        var apxSource = """
                app UT (
                    name: Universal Theme 26.1 Reference
                    version: 26.1.0
                    // ... removed code ...
                    authorization {
                        runOnPublicPages: true
                    }
                    security {
                        deepLinking: true
                        embedInFrames: allow
                        runtimeApiUsage: modifyThisApp
                    }
                    sessionStateProtection {
                        allowUrlsCreatedAfter: 1999-08-04T00:00:00
                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365
                    }
                    // ... removed code ...
                )
                """;
        var doc = ApexLangDocument.parse(apxSource);
        var violations = doc.getAllContentsOfType(ApexLangParser.PropertyContext.class)
                .stream()
                .filter(p -> p.name.getText().equals("embedInFrames")
                        &amp;&amp; p.value().getText().equals("allow"))
                .toList();
        for (var violation : violations) {
            System.err.println("Found vulnerability: " + violation.getText());
        }
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">//DEPS com.grisselbav:apexlang-parser:0.2.0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> com.grisselbav.apexlang.grammar.*;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DemoFindVulnerability</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4">[] </span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">apxSource</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">                app UT (</span></span>
<span class="line"><span style="color: #CE9178">                    name: Universal Theme 26.1 Reference</span></span>
<span class="line"><span style="color: #CE9178">                    version: 26.1.0</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                    authorization {</span></span>
<span class="line"><span style="color: #CE9178">                        runOnPublicPages: true</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    security {</span></span>
<span class="line"><span style="color: #CE9178">                        deepLinking: true</span></span>
<span class="line"><span style="color: #CE9178">                        embedInFrames: allow</span></span>
<span class="line"><span style="color: #CE9178">                        runtimeApiUsage: modifyThisApp</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    sessionStateProtection {</span></span>
<span class="line"><span style="color: #CE9178">                        allowUrlsCreatedAfter: 1999-08-04T00:00:00</span></span>
<span class="line"><span style="color: #CE9178">                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                )</span></span>
<span class="line"><span style="color: #CE9178">                &quot;&quot;&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">ApexLangDocument</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">parse</span><span style="color: #D4D4D4">(apxSource);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violations</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getAllContentsOfType</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">PropertyContext</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">stream</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">filter</span><span style="color: #D4D4D4">(p </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;embedInFrames&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">value</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;allow&quot;</span><span style="color: #D4D4D4">))</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">toList</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">:</span><span style="color: #D4D4D4"> violations) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Found vulnerability: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">());</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">This program embeds the APEXlang source code to scan in the <code>apxSource</code> variable. To run the program, save it as <code>DemoFindVulnerability.java</code>, then run it with <a href="https://www.jbang.dev/" type="link" id="https://www.jbang.dev/" target="_blank" rel="noreferrer noopener">JBang</a>. This will automatically resolve the Maven dependency on the first line.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>jbang DemoFindVulnerability.java</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">jbang</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">DemoFindVulnerability.java</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;jbang&#93; Resolving dependencies...
&#91;jbang&#93;    com.grisselbav:apexlang-parser:0.2.0
&#91;jbang&#93; Dependencies resolved
&#91;jbang&#93; Building jar for DemoFindVulnerability.java...
Found vulnerability: 
        embedInFrames: allow</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;jbang&#93; Resolving dependencies...</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;jbang&#93;    com.grisselbav:apexlang-parser:0.2.0</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;jbang&#93; Dependencies resolved</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;jbang&#93; Building jar for DemoFindVulnerability.java...</span></span>
<span class="line"><span style="color: #D4D4D4">Found vulnerability: </span></span>
<span class="line"><span style="color: #D4D4D4">        embedInFrames: allow</span></span></code></pre></div>



<h2 id="are-regular-expressions-an-alternative" class="wp-block-heading">Are Regular Expressions An Alternative?</h2>



<p class="wp-block-paragraph">In this case, we could have used a regular expression to identify the violation. </p>



<p class="wp-block-paragraph">However, as soon as the rules become more complicated, e.g. if we want to ensure that the property is part of the <code>security</code> group and the <code>security</code> group is part of the <code>app</code> component, regular expressions are no longer suited. But a parser is. Because we can navigate the parse tree and adjust the filter settings as follows.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">6) DemoFindVulnerability2.java with extended filter</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>//DEPS com.grisselbav:apexlang-parser:0.2.0

import com.grisselbav.apexlang.grammar.*;

class DemoFindVulnerability2 {
    public static void main(String[] args) {
        var apxSource = """
                app UT (
                    name: Universal Theme 26.1 Reference
                    version: 26.1.0
                    // ... removed code ...
                    authorization {
                        runOnPublicPages: true
                    }
                    security {
                        deepLinking: true
                        embedInFrames: allow
                        runtimeApiUsage: modifyThisApp
                    }
                    sessionStateProtection {
                        allowUrlsCreatedAfter: 1999-08-04T00:00:00
                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365
                    }
                    // ... removed code ...
                )
                """;
        var doc = ApexLangDocument.parse(apxSource);
        var violations = doc.getAllContentsOfType(ApexLangParser.PropertyContext.class)
                .stream()
                .filter(p -> p.name.getText().equals("embedInFrames")
                        &amp;&amp; p.value().getText().equals("allow")
                        &amp;&amp; p.parent.parent instanceof ApexLangParser.GroupContext g
                        &amp;&amp; g.name.getText().equals("security")
                        &amp;&amp; g.parent.parent.parent instanceof ApexLangParser.ComponentContext c
                        &amp;&amp; c.type.getText().equals("app"))
                .toList();
        for (var violation : violations) {
            System.err.println("Found vulnerability: " + violation.getText());
        }
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">//DEPS com.grisselbav:apexlang-parser:0.2.0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> com.grisselbav.apexlang.grammar.*;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DemoFindVulnerability2</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4">[] </span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">apxSource</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">                app UT (</span></span>
<span class="line"><span style="color: #CE9178">                    name: Universal Theme 26.1 Reference</span></span>
<span class="line"><span style="color: #CE9178">                    version: 26.1.0</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                    authorization {</span></span>
<span class="line"><span style="color: #CE9178">                        runOnPublicPages: true</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    security {</span></span>
<span class="line"><span style="color: #CE9178">                        deepLinking: true</span></span>
<span class="line"><span style="color: #CE9178">                        embedInFrames: allow</span></span>
<span class="line"><span style="color: #CE9178">                        runtimeApiUsage: modifyThisApp</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    sessionStateProtection {</span></span>
<span class="line"><span style="color: #CE9178">                        allowUrlsCreatedAfter: 1999-08-04T00:00:00</span></span>
<span class="line"><span style="color: #CE9178">                        checksumSalt: 75BAAC4002F8CA56EF54FD242CCE7719B1AB85BE339E930260B3EC8EA3879365</span></span>
<span class="line"><span style="color: #CE9178">                    }</span></span>
<span class="line"><span style="color: #CE9178">                    // ... removed code ...</span></span>
<span class="line"><span style="color: #CE9178">                )</span></span>
<span class="line"><span style="color: #CE9178">                &quot;&quot;&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">ApexLangDocument</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">parse</span><span style="color: #D4D4D4">(apxSource);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violations</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">doc</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getAllContentsOfType</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">PropertyContext</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">stream</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">filter</span><span style="color: #D4D4D4">(p </span><span style="color: #569CD6">-&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;embedInFrames&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">value</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;allow&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">instanceof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">GroupContext</span><span style="color: #D4D4D4"> g</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;security&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">g</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">instanceof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ApexLangParser</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ComponentContext</span><span style="color: #D4D4D4"> c</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                        &amp;&amp; </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">equals</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;app&quot;</span><span style="color: #D4D4D4">))</span></span>
<span class="line"><span style="color: #D4D4D4">                .</span><span style="color: #DCDCAA">toList</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">:</span><span style="color: #D4D4D4"> violations) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">println</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Found vulnerability: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">violation</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getText</span><span style="color: #D4D4D4">());</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h2 id="integration-into-dblinter" class="wp-block-heading">Integration Into dbLinter</h2>



<p class="wp-block-paragraph">The APEX-SERT &#8220;Embed in Frames&#8221; rule has been added to the dbLinter repository as rule <a href="https://dblinter.app/ords/r/dblinter/dblinter-console/rules#P1000_SHOW_RULE=core%20a-0770" target="_blank" rel="noreferrer noopener">A-0770: Never allow application pages within an HTML frame</a>. The VS Code extension, the CLI and the SonarQube plugin now support checks implemented for APEXlang.</p>



<p class="wp-block-paragraph">Here&#8217;s a short silent video that demonstrates how this security vulnerability is detected and quickly fixed.</p>



<figure class="wp-block-video"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls src="https://www.salvis.com/blog/wp-content/uploads/2026/06/dblinter-a1010.mp4"></video></figure>



<h2 id="conclusion" class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">The APEXlang grammar is intentionally simple through focusing on structural elements, leaving semantic validation, such as valid property values, to the APEXlang compiler in SQLcl, SQL Developer and VS Code.</p>



<p class="wp-block-paragraph">Integrating the APEXlang parser into dbLinter was straightforward, as was implementing the first APEXlang-based dbLinter rule.</p>



<p class="wp-block-paragraph">The next step is to identify which additional rules would be beneficial to bring to dbLinter. If you have any suggestions, please let me know. Even better, open a GitHub issue in the <a href="https://github.com/Grisselbav/dbLinter" target="_blank" rel="noreferrer noopener">dbLinter GitHub repository</a>. </p>



<p class="wp-block-paragraph">Thank you.</p>



<p class="wp-block-paragraph"><em>Updated on 2026-07-29, fixed link to rule &#8220;Never allow application pages within an HTML frame&#8221; (A-1010 → A-0770).</em></p>
<p>The post <a href="https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/">Detecting Security Vulnerabilities With the APEXlang Parser</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2026/06/29/detecting-security-vulnerabilities-with-the-apexlang-parser/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://www.salvis.com/blog/wp-content/uploads/2026/06/dblinter-a1010.mp4" length="2752429" type="video/mp4" />

			</item>
		<item>
		<title>Syntax Diagrams for APEXlang</title>
		<link>https://www.salvis.com/blog/2026/06/19/syntax-diagrams-for-apexlang/</link>
					<comments>https://www.salvis.com/blog/2026/06/19/syntax-diagrams-for-apexlang/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Fri, 19 Jun 2026 14:22:37 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[APEXlang]]></category>
		<category><![CDATA[dbLinter]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=19515</guid>

					<description><![CDATA[<p>Introduction The APEXlang API Reference documentation went live a few days ago. You can also download the APEXlang EBNF grammar. In this post, Kris Rice explains the value of having an EBNF. Since the APEXlang grammar is available as EBNF, it can be used to generate syntax diagrams. These diagrams (also known<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/06/19/syntax-diagrams-for-apexlang/">Syntax Diagrams for APEXlang</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">The <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/" target="_blank" rel="noreferrer noopener">APEXlang API Reference documentation</a> went live a few days ago. You can also download the APEXlang EBNF grammar. In <a href="https://www.linkedin.com/pulse/apexlang-now-has-published-ebnf-grammar-heres-what-unlocks-kris-rice-5tsoc/" type="link" id="https://www.linkedin.com/pulse/apexlang-now-has-published-ebnf-grammar-heres-what-unlocks-kris-rice-5tsoc/" target="_blank" rel="noreferrer noopener">this post</a>, Kris Rice explains the value of having an EBNF.</p>



<p class="wp-block-paragraph">Since the APEXlang grammar is available as EBNF, it can be used to generate <a href="https://en.wikipedia.org/wiki/Syntax_diagram" type="link" id="https://en.wikipedia.org/wiki/Syntax_diagram" target="_blank" rel="noreferrer noopener">syntax diagrams</a>. These diagrams (also known as railroad diagrams) make the language easier to explore and provide a visual complement to the API Reference.</p>



<p class="wp-block-paragraph">In this blog post, I explain how to produce the syntax diagrams for APEXlang. </p>



<h2 id="what-is-ebnf" class="wp-block-heading">What Is EBNF</h2>



<p class="wp-block-paragraph">Wikipedia describes the <a href="https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form" target="_blank" rel="noreferrer noopener">Extended Backus-Naur Form</a>. However, it&#8217;s important to notice that there are several variants of EBNF. </p>



<h2 id="apexlang-ebnf" class="wp-block-heading">APEXlang EBNF</h2>



<p class="wp-block-paragraph">The APEXlang EBNF grammar uses a variant of the BNF in the SQL:2023 standard, with some extensions explained at the top of the <a href="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/apexlang.ebnf" type="link" id="https://docs.oracle.com/en/database/oracle/apex/26.1/apxln/apexlang.ebnf" target="_blank" rel="noreferrer noopener">apexlang.ebnf</a> file.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">1) Syntax conventions in apexlang.ebnf</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>(* Syntax conventions
   &lt;nl> is significant: component declarations, groups, properties, and closing delimiters are line-oriented.
   &#91; X &#93; means optional X. { X } means zero or more X. A | B means either A or B.
*)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">(* Syntax conventions</span></span>
<span class="line"><span style="color: #6A9955">   &lt;nl&gt; is significant: component declarations, groups, properties, and closing delimiters are line-oriented.</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">   &#91; X &#93; means optional X. { X } means zero or more X. A | B means either A or B.</span></span>
<span class="line"><span style="color: #6A9955">*)</span></span></code></pre></div>



<p class="wp-block-paragraph">Square brackets <code>[]</code> indicate optionality, while curly brackets <code>{}</code> enclose a repeated group as defined in <a href="https://www.cl.cam.ac.uk/~mgk25/iso-14977.pdf" target="_blank" rel="noreferrer noopener">ISO/IEC 14977</a>. However, the <code>apexlang.ebnf</code> file does not fully use this ISO EBNF standard. <code>apexlang.ebnf</code> uses <code>::=</code> while the ISO standard uses a simple <code>=</code> for symbol definitions. This variant resembles a <a href="https://en.wikipedia.org/wiki/Wirth_syntax_notation" target="_blank" rel="noreferrer noopener">Wirth EBNF</a> with comments.</p>



<p class="wp-block-paragraph">Here&#8217;s the definition of the <code>app</code> rule in the <code>apexlang.ebnf</code> file.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-start:248;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">2) app rule in apexlang.ebnf</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;app> ::= "app" &#91; &lt;required-ws> &lt;component-id> &#93; &lt;ws> "(" &lt;line-end> { &lt;app-body-line> } &lt;indent> ")" &lt;line-end></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">app</span><span style="color: #569CD6">&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">::=</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;app&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&#91;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">required</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">ws</span><span style="color: #569CD6">&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">component</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">id</span><span style="color: #569CD6">&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&#93;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">ws</span><span style="color: #569CD6">&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;(&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">line</span><span style="color: #569CD6">-end&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">app</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">body</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">line</span><span style="color: #569CD6">&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">indent</span><span style="color: #569CD6">&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;)&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&lt;</span><span style="color: #D4D4D4">line</span><span style="color: #569CD6">-end&gt;</span></span></code></pre></div>



<h2 id="syntax-diagram" class="wp-block-heading">Syntax Diagram</h2>



<p class="wp-block-paragraph">This is the syntax diagram, or railroad diagram, for the app rule.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/06/app.svg"><img decoding="async" src="https://www.salvis.com/blog/wp-content/uploads/2026/06/app.svg" alt="" class="wp-image-19562"/></a></figure>



<p class="wp-block-paragraph">I produced this syntax diagram with the <a href="https://www.bottlecaps.de/rr/ui" target="_blank" rel="noreferrer noopener">Railroad Diagram Generator (RR)</a> by Gunter Rademacher. However, this tool requires a <a href="https://www.w3.org/TR/xml/#sec-notation">W3</a><a href="https://www.w3.org/TR/xml/#sec-notation" target="_blank" rel="noreferrer noopener">C EBNF</a> as input. In other words, the original <code>apexlang.ebnf</code> produces runtime errors. </p>



<h2 id="w3c-ebnf" class="wp-block-heading">W3C EBNF</h2>



<p class="wp-block-paragraph">Fortunately, it is straightforward to convert the APEXlang EBNF grammar to W3C EBNF. For the current APEXlang grammar, the conversion can be performed entirely through automated text transformations without manual edits.</p>



<p class="wp-block-paragraph">Here is a list of the most important replacement actions:</p>



<figure class="wp-block-table is-style-regular"><table><thead><tr><th class="has-text-align-left" data-align="left">Action</th><th class="has-text-align-left" data-align="left">Example From</th><th class="has-text-align-left" data-align="left">Example To</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left">Replace multiline comments</td><td class="has-text-align-left" data-align="left"><code>(* ... *)</code></td><td class="has-text-align-left" data-align="left"><code>/* ... */</code></td></tr><tr><td class="has-text-align-left" data-align="left">Remove leading <code>&lt;</code> and trailing <code>></code> in symbol names</td><td class="has-text-align-left" data-align="left"><code>&lt;app></code></td><td class="has-text-align-left" data-align="left"><code>app</code></td></tr><tr><td class="has-text-align-left" data-align="left">Use expression and <code>?</code> to express optionality</td><td class="has-text-align-left" data-align="left"><code>[ ... ]</code></td><td class="has-text-align-left" data-align="left"><code>( ... )?</code></td></tr><tr><td class="has-text-align-left" data-align="left">Use expression and <code>*</code> for repetitions</td><td class="has-text-align-left" data-align="left"><code>{ ... }</code></td><td class="has-text-align-left" data-align="left"><code>( ... )*</code></td></tr></tbody></table></figure>



<p class="wp-block-paragraph">The rule <code>app</code> in W3C EBNF looks as follows after applying these changes:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-start:248;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">3) app rule in apexlang.w3c.ebnf</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>app ::= "app" ( required-ws component-id )? ws "(" line-end ( app-body-line )* indent ")" line-end</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">app </span><span style="color: #569CD6">::=</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;app&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">(</span><span style="color: #D4D4D4"> required</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">ws component</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">id </span><span style="color: #569CD6">)</span><span style="color: #D4D4D4">? ws </span><span style="color: #CE9178">&quot;(&quot;</span><span style="color: #D4D4D4"> line</span><span style="color: #569CD6">-end</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">(</span><span style="color: #D4D4D4"> app</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">body</span><span style="color: #569CD6">-</span><span style="color: #D4D4D4">line </span><span style="color: #569CD6">)*</span><span style="color: #D4D4D4"> indent </span><span style="color: #CE9178">&quot;)&quot;</span><span style="color: #D4D4D4"> line</span><span style="color: #569CD6">-end</span></span></code></pre></div>



<p class="wp-block-paragraph">See <a href="https://github.com/Grisselbav/APEXlang/blob/main/Convert.java" type="link" id="https://github.com/Grisselbav/APEXlang/blob/main/Convert.java" target="_blank" rel="noreferrer noopener">Convert.java</a> for the complete conversion program. </p>



<h2 id="syntax-diagrams-on-github" class="wp-block-heading">Syntax Diagrams on GitHub</h2>



<p class="wp-block-paragraph">You cannot produce the complete syntax diagrams in the online version of the Railroad Diagram Generator because the APEXlang grammar is huge, and you will get a timeout when trying.</p>



<p class="wp-block-paragraph">So, you need to run the tool locally. I&#8217;ve created a <a href="https://github.com/Grisselbav/APEXlang/blob/main/.github/workflows/ci.yml" type="link" id="https://github.com/Grisselbav/APEXlang/blob/main/.github/workflows/ci.yml" target="_blank" rel="noreferrer noopener">GitHub workflow</a> that downloads <code>apexlang.ebnf</code>, converts it to a W3C EBNF, and generates an HTML file containing all syntax diagrams. Finally, the workflow publishes the result:</p>



<ul class="wp-block-list">
<li><a href="https://grisselbav.github.io/APEXlang/apexlang.w3c.ebnf.txt" target="_blank" rel="noreferrer noopener">APEXlang grammar converted to W3C EBNF</a> </li>



<li><a href="https://grisselbav.github.io/APEXlang/apexlang.html#app" type="link" id="https://grisselbav.github.io/APEXlang/apexlang.html#app" target="_blank" rel="noreferrer noopener">APEXlang syntax diagrams produced by RR</a></li>
</ul>



<p class="wp-block-paragraph">The advantage of syntax diagrams is that they show all usages of a symbol, allowing you to navigate quickly to the relevant definition.</p>



<h2 id="outlook" class="wp-block-heading">Outlook</h2>



<p class="wp-block-paragraph">The next step is to build a parser for APEXlang and use this as the basis for linting. This would enable APEXlang source code to be automatically validated, helping both developers and AI agents to produce code that conforms to defined quality standards.</p>



<p class="wp-block-paragraph">Looking further ahead, we are considering providing full support for APEXlang within the <a href="https://www.united-codes.com/products/dblinter/" type="link" id="https://www.united-codes.com/products/dblinter/" target="_blank" rel="noreferrer noopener">dbLinter tool suite</a>. Currently, dbLinter analyses only SQL and PL/SQL code blocks embedded in APEXlang files. Full APEXlang support is a natural evolution. Stay tuned!</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2026/06/19/syntax-diagrams-for-apexlang/">Syntax Diagrams for APEXlang</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2026/06/19/syntax-diagrams-for-apexlang/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
	</channel>
</rss>
