<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
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/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/hrvoje-filakovic/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Fri, 03 Apr 2026 12:58:20 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>19277691https://infinum.com/uploads/2026/04/axios-npm-attack.webp</url>
				</image>
				<title>The Axios npm Attack: What It Means for Every JavaScript Project</title>
				<link>https://infinum.com/blog/axios-npm-supply-chain-attack/</link>
				<pubDate>Wed, 01 Apr 2026 13:00:03 +0000</pubDate>
				<dc:creator>Hrvoje Filaković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=19277691</guid>
				<description>
					<![CDATA[<p>axios is the JavaScript library most apps use to talk to the internet. On March 31, two malicious versions were quietly published to npm — and anyone who ran npm install during a three-hour window may have a remote access trojan on their machine. Full technical breakdown inside.</p>
<p>The post <a href="https://infinum.com/blog/axios-npm-supply-chain-attack/">The Axios npm Attack: What It Means for Every JavaScript Project</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-288"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-93">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-94'
	>
	On March 31, attackers compromised axios — a JavaScript library downloaded roughly 100 million times a week. Here&#8217;s what happened, who&#8217;s affected, and what to do now.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-97'
	>
	If you&#8217;ve never heard of axios, here&#8217;s the short version: it&#8217;s the library that most JavaScript applications use to talk to the internet. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-100'
	>
	Fetching data from an API, submitting a form, making a request to a backend service – axios handles it. It&#8217;s in frontend apps, backend services, CI pipelines, and internal tools. Chances are it&#8217;s somewhere in your stack right now, possibly several places.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-102">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-103'
	>
	<span class='screen-reader-text'>On March 31, 2026, axios—with roughly 100 million weekly downloads—became the vector for one of the most significant npm supply chain attacks in recent memory.</span><span aria-hidden='true'><strong>On March 31, 2026, axios—with roughly 100 million weekly downloads—became the vector for one of the most significant npm supply chain attacks in recent memory.</strong></span></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-106"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-105'
	>
	Two malicious versions of axios were published to npm: axios@1.14.1 and axios@0.30.4. Both contained a hidden dependency designed to install a cross-platform remote access trojan on any developer machine that ran npm install. The window was under three hours — but given axios&#8217;s scale, that was enough. If your team ships JavaScript and installed either version during that period, treat the affected machine as compromised.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-109"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-107">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-108'
	>
	<strong>You don’t need to have installed axios directly to be at risk. </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-112"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-110">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-111'
	>
	Any package in your dependency tree that lists axios with a floating version range (<code>^1.x</code>) and was rebuilt during the exposure window may have pulled in the malicious version automatically. This also includes AI coding assistants and automated tooling — anything that ran <code>npm install</code> on your behalf yesterday should be treated the same as a manual install.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-113">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-114'
	>
	We&#8217;ve written before about <a href="https://infinum.com/blog/software-supply-chain-security/">software supply chain security</a> and the systemic risks that come with modern dependency management. This attack is exactly the scenario we described – not a theoretical edge case, but a live incident affecting one of the most widely used libraries in the JavaScript ecosystem. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-118"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-116">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-117'
	>
	<a href="https://cloud.google.com/blog/topics/threat-intelligence/north-korea-threat-actor-targets-axios-npm-package" id="https://cloud.google.com/blog/topics/threat-intelligence/north-korea-threat-actor-targets-axios-npm-package">Google&#8217;s Threat Intelligence Group</a> has attributed the attack to UNC1069, a North Korean group previously active in cryptocurrency theft. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-121"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-119">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-120'
	>
	Here&#8217;s what happened, how it worked, and what you should check right now.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-124"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-122">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-123'
	>
	<strong>What happened</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-125">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-126'
	>
	The attacker didn&#8217;t touch a single line of axios source code. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-128">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-129'
	>
	Instead, they compromised a long-lived npm access token belonging to jasonsaayman, the project&#8217;s lead maintainer. With that token, they published two new releases – one for the 1.x branch and one for the legacy 0.x branch – 39 minutes apart, covering both release lines simultaneously.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-133"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-131">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-132'
	>
	Both releases modified exactly one file: package.json. The only substantive change was adding plain-crypto-js@4.2.1 as a runtime dependency. That package was pre-staged 18 hours earlier, under a separate attacker-controlled account, with a clean version first to build registry history before the malicious update was pushed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-135"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-134'
	>
	Why this matters: When you run npm install, you&#8217;re not just downloading the package you asked for — you&#8217;re downloading everything it depends on, including any setup scripts those dependencies declare. The attacker&#8217;s package declared one. Most developers never see this happening. It runs silently, by design. By the time npm install finished, the script had already executed, phoned home, and delivered its payload.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-138"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-136">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-137'
	>
	plain-crypto-js contains a full copy of the legitimate crypto-js library – every source file identical, bit-for-bit. The only difference is a postinstall hook: &#8220;node setup.js&#8221;. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-141"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-139">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-140'
	>
	When npm resolves the dependency tree and runs that hook, the dropper fires. It contacts the attacker&#8217;s command-and-control server, delivers a platform-specific payload for macOS, Windows, or Linux, then deletes itself and replaces package.json with a clean stub reporting version 4.2.0.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-144"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-142">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-143'
	>
	By the time npm install finishes, there&#8217;s no error, no warning, no obvious trace. The directory node_modules/plain-crypto-js/ exists, but npm list shows version 4.2.0 – not the malicious 4.2.1 that actually ran. Standard npm audit finds nothing.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-147"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-145">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-146'
	>
	<strong>Why this specific attack is worth studying</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-150"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-148">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-149'
	>
	Most supply chain incidents involve obvious red flags – a zero-history package, a suspicious name, a sudden maintainer change. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-151">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-152'
	>
	This one was deliberately engineered to avoid all of them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-158"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-154">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-155'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-156'
	>
	<strong>Put plainly: most security tools work by recognising known bad things – a flagged domain, a suspicious file, a package with no history. This attack had none of those signals. It arrived under a trusted name, from a legitimate account, with clean source code and a registry history. The tools that were supposed to catch it passed it through.</strong></p>
		<div class="blockquote__caption-wrap">
			<div	class='typography typography--size-12-text-roman js-typography blockquote__caption'
	data-id='es-157'
	>
	HRVOJE FILAKOVIC, CYBERSECURITY ENGINEER</div>		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-161"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-159">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-160'
	>
	That&#8217;s what makes it worth paying attention to, even if axios isn&#8217;t in your stack – the technique will be reused.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-162">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-163'
	>
	The attacker published a clean decoy package 18 hours before activating the payload – long enough to avoid &#8220;brand new account&#8221; alerts from registry scanners. The malicious axios releases were signed by the legitimate maintainer&#8217;s account. No corresponding commit or tag appeared on GitHub (that gap is the forensic signal, in hindsight), but most CI systems don&#8217;t verify OIDC provenance on pull.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-166"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-165'
	>
	The plain-crypto-js package was designed to survive a human code review. The library files were identical to the legitimate crypto-js. A developer diffing the package against its stated source would find nothing. The malicious payload lived in package.json and setup.js – a postinstall script that looks, at a glance, like a standard build step.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-169"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-167">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-168'
	>
	This is the attack pattern that <a href="https://infinum.com/blog/eu-cybersecurity-legislation-nis2-dora/">NIS2</a> and <a href="https://infinum.com/blog/cyber-resilience-act/">CRA</a> regulations are increasingly focused on: not a breach of your perimeter, but a compromise of the supply chain your code depends on. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-172"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-170">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-171'
	>
	Your code didn&#8217;t have a vulnerability. Your tooling did.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-173">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-174'
	>
	<strong>The OIDC misconfiguration that made it possible</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-176">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-177'
	>
	Axios had OIDC Trusted Publishing configured for its release workflow. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-181"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-179">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-180'
	>
	In theory, this should have made a token-based publish impossible – OIDC ties releases to specific GitHub Actions runs, and the ephemeral token can&#8217;t be stolen.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-184"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-182">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-183'
	>
	In practice, the GitHub Actions workflow passed both the OIDC credentials and a classic NPM_TOKEN environment variable. When both are present, npm defaults to the token. The long-lived token – which can be exfiltrated – was effectively the only authentication method that mattered.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-187"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-185">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-186'
	>
	This is a common misconfiguration. Many projects enable OIDC Trusted Publishing and consider the job done, without removing or rotating the classic token that overrides it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-190"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-188">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-189'
	>
	<strong>Check if you&#8217;re affected – right now</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-193"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-191">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-192'
	>
	<strong>Step 1 – Check your lockfile for the malicious versions</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">grep</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">E</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">&quot;axios&quot;</span><span class="token" style="color: #032f62;">&#039;</span><span class="token"> </span><span class="token" style="color: #005cc5;">package</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">lock</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">json</span><span class="token"> </span><span class="token" style="color: #d73a49;">|</span><span class="token"> </span><span class="token" style="color: #005cc5;">grep</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">E</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">1\.14\.1|0\.30\.4</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">npm</span><span class="token"> </span><span class="token" style="color: #005cc5;">list</span><span class="token"> </span><span class="token" style="color: #005cc5;">axios</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">dev</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">null</span><span class="token"> </span><span class="token" style="color: #d73a49;">|</span><span class="token"> </span><span class="token" style="color: #005cc5;">grep</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">E</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">1\.14\.1|0\.30\.4</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-196">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-197'
	>
	<strong>Step 2 – Check for the malicious dependency in node_modules</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-199">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-200'
	>
	The presence of this directory – regardless of what version package.json now reports – means the dropper executed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-203"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">ls</span><span class="token"> </span><span class="token" style="color: #005cc5;">node_modules</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">plain</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">crypto</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">js</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">dev</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">null</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">echo</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">DROPPER RAN</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-206"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-204">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-205'
	>
	<strong>Step 3 – Check for persistent artifacts</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-208"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> macOS</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #005cc5;">ls</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">la</span><span class="token"> </span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">Library</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">Caches</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">com</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">apple</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">act</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">mond</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">dev</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">null</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">echo</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">COMPROMISED</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> Linux</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #005cc5;">ls</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">la</span><span class="token"> </span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">tmp</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">ld</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">py</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">dev</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">null</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">echo</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">COMPROMISED</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> Windows (cmd.exe)</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #005cc5;">dir</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">%PROGRAMDATA%\wt.exe</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token" style="color: #005cc5;">nul</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">echo</span><span class="token"> </span><span class="token" style="color: #005cc5;">COMPROMISED</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-211"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-209">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-210'
	>
	<strong>If you find any of these</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-214"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-212">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-213'
	>
	The response depends on where the install ran. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-217"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-215">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-216'
	>
	For <strong>ephemeral CI runners</strong> (e.g. GitHub-hosted), the runner is destroyed after each job — rotate any secrets that were injected during the affected run and move on. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-220"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-218">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-219'
	>
	For <strong>developer machines and self-hosted runners</strong>, treat the system as fully compromised: isolate it from the network immediately and re-image it or restore from a verified clean backup taken before March 30. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-222"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-221'
	>
	<strong>Do not attempt to clean in place — the RAT deploys persistence mechanisms that survive a reboot, so credential rotation on a live system is not sufficient.</strong> </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-225"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-223">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-224'
	>
	Once you have a clean machine, rotate everything that was accessible from it: npm tokens, SSH keys, cloud credentials (AWS, GCP, Azure), CI/CD secrets, and any values in <code>.env</code> files present at install time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-228"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-226">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-227'
	>
	<strong>To downgrade cleanly</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">npm</span><span class="token"> </span><span class="token" style="color: #005cc5;">install</span><span class="token"> </span><span class="token" style="color: #005cc5;">axios</span><span class="token" style="color: #d73a49;">@</span><span class="token" style="color: #005cc5;">1</span><span class="token" style="color: #005cc5;">.</span><span class="token" style="color: #005cc5;">14</span><span class="token" style="color: #005cc5;">.</span><span class="token" style="color: #005cc5;">0</span><span class="token">  </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> for 1.x users</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #005cc5;">npm</span><span class="token"> </span><span class="token" style="color: #005cc5;">install</span><span class="token"> </span><span class="token" style="color: #005cc5;">axios</span><span class="token" style="color: #d73a49;">@</span><span class="token" style="color: #005cc5;">0</span><span class="token" style="color: #005cc5;">.</span><span class="token" style="color: #005cc5;">30</span><span class="token" style="color: #005cc5;">.</span><span class="token" style="color: #005cc5;">3</span><span class="token">  </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> for 0.x users</span><span class="token" style="color: #6a737d;">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-233"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-231">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-232'
	>
	<strong>What to change in your CI/CD configuration</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-236"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-234">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-235'
	>
	Beyond the immediate incident, this attack exposes a few controls worth auditing across your pipelines.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-239"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-237">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-238'
	>
	<li><strong>Remove or rotate long-lived npm tokens. </strong>If your publish workflow uses a classic NPM_TOKEN alongside OIDC, the token wins. Either remove it from the workflow entirely, or rotate it and restrict it to the minimum necessary scope.</li><li><strong>Add &#8211;ignore-scripts to CI installs. </strong>This prevents postinstall hooks from running during automated builds:</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-241"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">npm</span><span class="token"> </span><span class="token" style="color: #005cc5;">ci</span><span class="token"> </span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #005cc5;">ignore</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">scripts</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-244"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-242">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-243'
	>
	<li><strong>Pin versions explicitly. </strong>Avoid floating ranges like ^1.14.0. Both malicious releases were tagged latest, so any unpinned install resolved to them.</li><li><strong>Add provenance verification to your review process. </strong>For major releases of critical packages, check npm registry metadata for OIDC provenance. Legitimate axios 1.x releases show GitHub Actions as the publisher with a trustedPublisher field. The malicious release showed the maintainer&#8217;s username directly – no OIDC binding, no corresponding GitHub tag.</li><li><strong>Block the C2 domain at the network level</strong>. If you have a firewall or DNS filtering in place, block the C2 domain <code>sfrclak[.]com</code> and IP address <code>142[.]11[.]206[.]73</code> on port 8000. Flag this to your network or DevOps team rather than handling it at the host level — a firewall rule covers all machines rather than requiring per-device changes.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-247"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-245">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-246'
	>
	<strong>The broader pattern</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-250"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-248">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-249'
	>
	This isn&#8217;t an isolated incident. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-253"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-251">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-252'
	>
	The axios attack follows the same playbook as the <a href="https://infinum.com/blog/crowdstrike-3-takeaways/" id="https://infinum.com/blog/crowdstrike-3-takeaways/">CrowdStrike npm compromise</a>, the IoliteLabs VSCode extension backdoor from a few days earlier, and dozens of similar incidents over the past two years. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-255"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-254'
	>
	The package manager ecosystem runs on implicit trust: if a package is in npm under a recognizable name and a legitimate maintainer&#8217;s account, most tooling and most developers treat it as safe.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-256">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-257'
	>
	That model is under sustained attack. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-259">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-260'
	>
	The attacker here invested 18 hours of prep time, built platform-specific payloads for three operating systems, and designed the dropper to self-destruct. This is not someone experimenting – it&#8217;s operational tradecraft applied to the JavaScript supply chain.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-262">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-263'
	>
	As we covered in our <a href="https://infinum.com/blog/software-supply-chain-security/">supply chain security framework</a>, the highest-risk entry points are often not your own code but the tools and processes you depend on to build and deploy it. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-267"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-265">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-266'
	>
	The question isn&#8217;t whether your perimeter is secure, it&#8217;s whether your CI pipeline would have caught this before it ran.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-270"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-268">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-269'
	>
	<strong>For teams with third-party risk exposure</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-271">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-272'
	>
	If you&#8217;re managing a product that runs JavaScript in CI and you have compliance obligations – PCI DSS, NIS2, ISO 27001 – this incident is worth documenting even if you weren&#8217;t affected. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-274">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-275'
	>
	Our <a href="https://infinum.com/third-party-cyber-risk-management/">third-party cyber risk management</a> work often starts with incidents like this one: not after a breach, but as a trigger to audit what dependency hygiene actually looks like in practice across an engineering org.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-279"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-277">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-278'
	>
	The controls that would have caught this – OIDC provenance checks, version pinning, &#8211;ignore-scripts in CI, outbound network monitoring – aren&#8217;t difficult to implement. They just tend not to exist until something goes wrong.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-282"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-280">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-281'
	>
	If you want to review your current posture, <a href="https://infinum.com/contact/">get in touch</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-285"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-283">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-284'
	>
	<strong>Indicators of compromise</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-286"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			
<figure class="wp-block-table is-style-stripes"><table><tbody><tr><td><strong>Malicious packages</strong></td><td></td></tr><tr><td>Malicious package</td><td>axios@1.14.1 (shasum: 2553649f)</td></tr><tr><td>Malicious package</td><td>axios@0.30.4 (shasum: d6f3f62f)</td></tr><tr><td>Malicious dependency</td><td>plain-crypto-js@4.2.1</td></tr><tr><td>Attacker npm account</td><td>jasonsaayman (email changed to ifstap[at]proton[.]me)</td></tr><tr><td>Staging npm account</td><td>nrwise (email: nrwise[at]proton[.]me)</td></tr><tr><td><strong>Network indicators</strong></td><td></td></tr><tr><td>C2 domain</td><td>sfrclak[.]com</td></tr><tr><td>C2 IP</td><td>142[.]11[.]206[.]73</td></tr><tr><td>C2 URL</td><td>hxxp://sfrclak[.]com:8000/6202033</td></tr><tr><td>C2 port</td><td>8000</td></tr><tr><td>macOS POST body</td><td>packages.npm[.]org/product0</td></tr><tr><td>Windows POST body</td><td>packages.npm[.]org/product1</td></tr><tr><td>Linux POST body</td><td>packages.npm[.]org/product2</td></tr><tr><td><strong>Filesystem artifacts</strong></td><td></td></tr><tr><td>macOS artifact</td><td>/Library/Caches/com.apple.act.mond</td></tr><tr><td>Windows (persistent)</td><td>%PROGRAMDATA%\wt.exe</td></tr><tr><td>Windows temp (self-deletes)</td><td>%TEMP%\6202033.vbs | %TEMP%\6202033.ps1</td></tr><tr><td>Linux artifact</td><td>/tmp/ld.py</td></tr><tr><td><strong>Advisory references</strong></td><td></td></tr><tr><td>GitHub advisory</td><td>GHSA-fw8c-xr5c-95f9</td></tr><tr><td>Malware advisory</td><td>MAL-2026-2306</td></tr><tr><td>Malware family (GTIG)</td><td>WAVESHAPER.V2</td></tr><tr><td><strong>Safe versions</strong></td><td></td></tr><tr><td>Safe 1.x version</td><td>axios@1.14.0 (shasum: 7c29f4cf)</td></tr><tr><td>Safe 0.x version</td><td>axios@0.30.3</td></tr></tbody></table><figcaption class="wp-element-caption"><em>Infinum&#8217;s cybersecurity team provides penetration testing, third-party risk management, and secure development advisory for enterprise and regulated-industry clients. Learn more at </em><a href="https://infinum.com/cybersecurity/"><em>infinum.com/cybersecurity</em></a><em>.</em></figcaption></figure>
	</div>


</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/axios-npm-supply-chain-attack/">The Axios npm Attack: What It Means for Every JavaScript Project</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>19276916https://infinum.com/uploads/2026/03/android-protection-hero-2.webp</url>
				</image>
				<title>Understanding &#038; Defeating Android Protections</title>
				<link>https://infinum.com/blog/understanding-defeating-android-protections/</link>
				<pubDate>Thu, 19 Mar 2026 11:13:28 +0000</pubDate>
				<dc:creator>Hrvoje Filaković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=19276916</guid>
				<description>
					<![CDATA[<p>Discover how hackers bypass Android root detection, anti-hooking, and anti-debug protections with real code examples and penetration testing techniques to strengthen your mobile security knowledge.</p>
<p>The post <a href="https://infinum.com/blog/understanding-defeating-android-protections/">Understanding &amp; Defeating Android Protections</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-733"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-289">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-292"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-290">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-291'
	>
	Many modern Android applications are highly advanced and operate in sensitive domains like banking, money transfers, and other critical services people rely on daily. A rooted environment gives attackers elevated access to the device, which they can abuse in order to bypass the app’s restrictions, extract sensitive data, and interfere with the app’s behavior.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-295"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-293">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-294'
	>
	To counter these threats, many apps implement protections against common tools and techniques used in reverse engineering. These include anti-root, anti-hook, and anti-debug mechanisms, which are designed to make an attacker’s job significantly more difficult—often requiring considerable effort and creativity to bypass.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-298"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-296">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-297'
	>
	<li>Anti-Root – Detects whether the device has been rooted.</li><li>Anti-Hook – Detects function hooking attempts using tools like Frida.</li><li>Anti-Debug – Detects whether the application is being debugged.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-301"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-299">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-300'
	>
	A practical look at protection mechanisms</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-304"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-302">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-303'
	>
	This article provides other security researchers with a practical look at how some of these protection mechanisms are implemented and how they can be bypassed during <a href="https://infinum.com/blog/penetration-testing-steps/" id="https://infinum.com/blog/penetration-testing-steps/">penetration testing</a> or security research.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-307"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-305">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-306'
	>
	Additionally, by understanding how these protections work, developers can <a href="https://infinum.com/blog/ssdlc-application-security/" id="https://infinum.com/blog/ssdlc-application-security/">build stronger, more resilient security mechanisms</a> into their apps and even extend these ideas to develop more advanced and effective techniques.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-310"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-308">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-309'
	>
	Furthermore, during this research, an application called TamperLab was created. It includes various protection mechanisms to detect whether a device is rooted, whether any hooking is in place, or whether the application is being debugged. The project is fully open-source, and contributions are welcome.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-311">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-312'
	>
	It can be found on the following GitHub page for you to check out:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-315"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-html github-light" data-language="html" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">https://github.com/infinum/cs-tamperlab
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-318"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-316"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-317">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2026/03/Screenshot-2026-03-17-at-11.23.01-1400x910.webp				media='(max-width: 699px)'
				type=image/webp								height="910"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2026/03/Screenshot-2026-03-17-at-11.23.01.webp"
					class="image__img block-media__image-img"
					alt="TamperLab Android app showing root detection, hook detection, and debug detection status indicators with green and red checkmarks"
										height="968"
															width="1490"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-321"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-319">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-320'
	>
	Anti-Root Protections</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-324"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-322">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-323'
	>
	In this section, we will look at some commonly used root detection techniques and their implementations, and immediately follow each one with an example of how it can be bypassed during testing or reverse engineering.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-327"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-325">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-326'
	>
	The “One Function” Folly</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-330"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-328">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-329'
	>
	The most common way of implementing protection measures such as anti-root, anti-hook, and anti-debug is by placing all checks inside a single function. This is a common mistake, as it gives attackers the opportunity to <a href="https://infinum.com/blog/ai-generated-code-security-risks/" id="https://infinum.com/blog/ai-generated-code-security-risks/">bypass all protections</a> within seconds.For example, in the following scenario, the <a href="https://github.com/scottyab/rootbeer">RootBeer</a> library is used to quickly demonstrate why placing all checks in a single function can be problematic. As shown in the code snippet below, the isRooted() function is called.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-332"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">boolean</span><span class="token"> </span><span class="token" style="color: #24292e;">isRooted</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">rootBeer</span><span class="token">.</span><span class="token" style="color: #6f42c1;">isRooted</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">showRootStatusDialog</span><span class="token">(</span><span class="token">isRooted</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-335"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-333">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-334'
	>
	Such a function includes various methods to detect if the device is rooted.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-337"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">boolean</span><span class="token"> </span><span class="token" style="color: #6f42c1;">isRooted</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #6f42c1;">detectRootManagementApps</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">||</span><span class="token"> 
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">detectPotentiallyDangerousApps</span><span class="token">(</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #d73a49;">||</span><span class="token"> 
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">checkForBinary</span><span class="token">(</span><span class="token">BINARY_SU</span><span class="token">)</span><span class="token">         </span><span class="token" style="color: #d73a49;">||</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">checkForDangerousProps</span><span class="token">(</span><span class="token">)</span><span class="token">          </span><span class="token" style="color: #d73a49;">||</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">checkForRWPaths</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-338">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-339'
	>
	Although the function includes many ways to detect if the device is rooted, it is not sufficient because the isRooted() function itself can be hooked, allowing an attacker to bypass all detections with a single hook.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-341">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-342'
	>
	Using the following simple Frida script, we can do exactly that. We obtain a reference to the RootBeer class and hook the isRooted() function, immediately returning false.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-345"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-javascript github-light" data-language="javascript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Java</span><span class="token">.</span><span class="token" style="color: #6f42c1;">perform</span><span class="token">(</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #005cc5;">rootbeer</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">Java</span><span class="token">.</span><span class="token" style="color: #6f42c1;">use</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">com.scottyab.rootbeer.RootBeer</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">rootbeer</span><span class="token">.</span><span class="token" style="color: #24292e;">isRooted</span><span class="token">.</span><span class="token" style="color: #6f42c1;">implementation</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">function</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">[+] isRooted() hooked -&gt; returning false</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-348"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-346">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-347'
	>
	Using the following command, the targeted application can be started with the hook applied.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-350"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">frida </span><span class="token" style="color: #d73a49;">-</span><span class="token">U </span><span class="token" style="color: #d73a49;">-</span><span class="token">l </span><span class="token" style="color: #24292e;">evade_root</span><span class="token">.</span><span class="token" style="color: #24292e;">js</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">f </span><span class="token" style="color: #24292e;">com</span><span class="token">.</span><span class="token" style="color: #24292e;">hacking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-353"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-351">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-352'
	>
	As shown in the following image, the previously created script successfully bypasses all the checks because they are contained within a single function.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-356"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-354"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-355">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_2.webp"
					class="image__img block-media__image-img"
					alt="Frida terminal output showing isRooted() hook successfully returning false, bypassing all RootBeer root checks with a single Frida script"
										height="311"
															width="745"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-359"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-357">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-358'
	>
	Testing this inside TamperLab shows that we successfully bypass the protection measure, and a green checkmark is displayed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-362"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-360"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-361">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_3.webp"
					class="image__img block-media__image-img"
					alt="TamperLab app displaying green checkmark after successful bypass of root detection using Frida isRooted() hook"
										height="310"
															width="478"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-365"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-363">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-364'
	>
	SU Binary Check (Shell)</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-368"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-366">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-367'
	>
	All rooted Android devices contain the su binary, and any application requiring root access must use su to elevate privileges and perform privileged actions on the device.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-371"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-369">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-370'
	>
	When present on a device, applications can detect the existence of the binary and conclude that the device is rooted. A quick way to check for it is by programmatically executing the which su system command.In my application, I created a simple HelperClass that contains various functionalities and detection methods. One of its purposes is to execute system commands.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-373"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">String</span><span class="token"> </span><span class="token" style="color: #24292e;">output</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">HelperClass</span><span class="token">.</span><span class="token" style="color: #6f42c1;">executeCommand</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">which su</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-376"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-374">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-375'
	>
	The executeCommand() function essentially passes the given command as an argument to the exec() function, which executes it on the device.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-378"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Process</span><span class="token"> </span><span class="token" style="color: #24292e;">process</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">Runtime</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getRuntime</span><span class="token">(</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">exec</span><span class="token">(</span><span class="token">command</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">BufferedReader</span><span class="token"> </span><span class="token" style="color: #24292e;">reader</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">new</span><span class="token"> </span><span class="token" style="color: #6f42c1;">BufferedReader</span><span class="token">(</span><span class="token" style="color: #d73a49;">new</span><span class="token"> </span><span class="token" style="color: #6f42c1;">InputStreamReader</span><span class="token">(</span><span class="token" style="color: #24292e;">process</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getInputStream</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">String</span><span class="token"> </span><span class="token" style="color: #24292e;">output</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">reader</span><span class="token">.</span><span class="token" style="color: #6f42c1;">readLine</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">reader</span><span class="token">.</span><span class="token" style="color: #6f42c1;">close</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">return</span><span class="token"> output</span><span class="token">;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-381"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-379">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-380'
	>
	If the su binary exists, the command will return its full system path, otherwise, an error code will be returned.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-384"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-382">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-383'
	>
	Using Frida, we can bypass this technique by hooking the exec() function itself. If we detect a command such as which su, we can replace it at runtime with another non-existent command.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-386"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Java</span><span class="token">.</span><span class="token" style="color: #6f42c1;">perform</span><span class="token">(</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">const</span><span class="token"> Runtime </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">Java</span><span class="token">.</span><span class="token" style="color: #6f42c1;">use</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">java.lang.Runtime</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">Runtime</span><span class="token">.</span><span class="token" style="color: #24292e;">exec</span><span class="token">.</span><span class="token" style="color: #6f42c1;">overload</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">java.lang.String</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #24292e;">implementation</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">command</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #24292e;">command</span><span class="token">.</span><span class="token" style="color: #6f42c1;">trim</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">===</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">which su</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">[i] called exec(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> command </span><span class="token" style="color: #d73a49;">+</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">)</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[+] returning a fake binary.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            command </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">which DoesNotExist</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #6f42c1;">exec</span><span class="token">(</span><span class="token">command</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #6f42c1;">exec</span><span class="token">(</span><span class="token">command</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-389"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-387">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-388'
	>
	As demonstrated, by using this technique, we can target specific exec() parameters after reverse engineering the application and bypass the detection mechanisms in place.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-392"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-390"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-391">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_4.webp"
					class="image__img block-media__image-img"
					alt="Frida script output intercepting Runtime.exec() call for &quot;which su&quot; command and substituting a non-existent binary path to bypass SU binary shell check"
										height="315"
															width="742"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-395"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-393">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-394'
	>
	SU Binary Check (Native C/C++)</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-398"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-396">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-397'
	>
	Another way developers may check for the su binary or for rooted devices in general is by writing native C/C++ code using JNI. In case you are unfamiliar, JNI (Java Native Interface) is a framework that allows Java code running on the Android platform to interact with native applications and libraries written in C or C++.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-401"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-399">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-400'
	>
	For example, we can check for the su binary by iterating through common system paths where it might exist, and then using the std::ifstream function to check if the file can be opened.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-403"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">extern </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">C</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #24292e;">JNIEXPORT</span><span class="token"> jboolean </span><span class="token" style="color: #24292e;">JNICALL</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">Java_com_hacking_tamperlab_NativeChecks_CheckSuBinaryNative</span><span class="token">(</span><span class="token">JNIEnv </span><span class="token" style="color: #d73a49;">*</span><span class="token">env</span><span class="token">,</span><span class="token"> jclass clazz</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #d73a49;">char</span><span class="token" style="color: #d73a49;">*</span><span class="token"> paths</span><span class="token">[</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/data/local/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/data/local/bin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/data/local/xbin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/sbin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/su/bin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/system/bin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/system/bin/.ext/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/system/bin/failsafe/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/system/sd/xbin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/system/usr/we-need-root/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/system/xbin/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/cache/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/data/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/dev/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Scan directories for &quot;su&quot; binary, if found return true.</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">for</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #d73a49;">char</span><span class="token" style="color: #d73a49;">*</span><span class="token"> path</span><span class="token" style="color: #d73a49;">:</span><span class="token"> paths</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        std</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token">string fullPath </span><span class="token" style="color: #d73a49;">=</span><span class="token"> std</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #6f42c1;">string</span><span class="token">(</span><span class="token">path</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">su</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        std</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token">ifstream </span><span class="token" style="color: #6f42c1;">file</span><span class="token">(</span><span class="token">fullPath</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #24292e;">file</span><span class="token">.</span><span class="token" style="color: #6f42c1;">good</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">file</span><span class="token">.</span><span class="token" style="color: #6f42c1;">close</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">return</span><span class="token"> JNI_TRUE</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> JNI_FALSE</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-406"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-404">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-405'
	>
	A small Java class is then created to serve as a bridge between the Java code and the native C/C++ code in the application. It uses JNI (Java Native Interface) to perform the native task.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-408"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">NativeChecks</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">static</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">System</span><span class="token">.</span><span class="token" style="color: #6f42c1;">loadLibrary</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">tamper-lib</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">static</span><span class="token"> </span><span class="token" style="color: #d73a49;">native</span><span class="token"> </span><span class="token" style="color: #d73a49;">boolean</span><span class="token"> </span><span class="token" style="color: #6f42c1;">CheckSuBinaryNative</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-411"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-409">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-410'
	>
	Under normal circumstances, you wouldn’t have access to the source code. However, a common way to reverse engineer the application is by decompiling it using <a href="https://github.com/skylot/jadx">JADX</a>, which can be done with the following command.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-413"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">$ jadx </span><span class="token" style="color: #d73a49;">-</span><span class="token">d </span><span class="token" style="color: #6f42c1;">$</span><span class="token">(</span><span class="token">pwd</span><span class="token">)</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #24292e;">TamperLab_Decompiled</span><span class="token"> </span><span class="token" style="color: #6f42c1;">$</span><span class="token">(</span><span class="token">pwd</span><span class="token">)</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #24292e;">TamperLab</span><span class="token">.</span><span class="token" style="color: #24292e;">apk</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-416"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-414">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-415'
	>
	Once decompiled, your application may contain various libraries. You can easily filter through them by searching for files with the .so extension, which indicates native libraries.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-418"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-html github-light" data-language="html" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">$ find TamperLab_Decompiled -type f -name &quot;*.so&quot;                        
</span></span><span class="line"><span class="token">TamperLab_Decompiled/resources/lib/arm64-v8a/libtamper-lib.so
</span></span><span class="line"><span class="token">TamperLab_Decompiled/resources/lib/arm64-v8a/libtoolChecker.so
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-421"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-419">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-420'
	>
	To reverse engineer the library, tools such as <a href="https://github.com/NationalSecurityAgency/ghidra">Ghidra</a> or <a href="https://hex-rays.com/ida-pro">IDA Pro</a> can be used. In this case, Ghidra was used.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-424"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-422"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-423">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_5.webp"
					class="image__img block-media__image-img"
					alt="Ghidra decompiled view of libtamper-lib.so native library showing ifstream file check logic, JNI_TRUE return (1) if su binary found, and JNI_FALSE return (0) if not found"
										height="675"
															width="877"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-427"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-425">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-426'
	>
	The decompiled code shows that ifstream is first used (1) to check whether the file exists. Based on this check, the function returns \x01 (JNI_TRUE) (2) if the su binary is found, otherwise, it returns \x00 (JNI_FALSE) (3).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-430"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-428">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-429'
	>
	Since this is a JNI function and is exposed using extern &#8220;C&#8221;, it appears in the symbol table with the exact name observed in Ghidra.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-432"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Java_com_hacking_tamperlab_NativeChecks_CheckSuBinaryNative</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-435"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-433">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-434'
	>
	Bypassing such checks is relatively straightforward. To hook a native function using Frida, we use Interceptor.attach() and specify the target function using Module.findExportByName().</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Interceptor</span><span class="token">.</span><span class="token" style="color: #6f42c1;">attach</span><span class="token">(</span><span class="token" style="color: #24292e;">Module</span><span class="token">.</span><span class="token" style="color: #6f42c1;">findExportByName</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">libtamper-lib.so</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Java_com_hacking_tamperlab_NativeChecks_CheckSuBinaryNative</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    onEnter</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token"> </span><span class="token">(</span><span class="token">args</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">[i] CheckSuBinaryNative() called</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    onLeave</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token"> </span><span class="token">(</span><span class="token">retval</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[+] Overriding return with JNI_FALSE</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">replace</span><span class="token">(</span><span class="token" style="color: #005cc5;">0</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-438">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-439'
	>
	Since we are intercepting a function from the native library, we need to attach to the process while it is already running by using the -n parameter with the following command.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-442"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">frida </span><span class="token" style="color: #d73a49;">-</span><span class="token">U </span><span class="token" style="color: #d73a49;">-</span><span class="token">l </span><span class="token" style="color: #24292e;">evade_root</span><span class="token">.</span><span class="token" style="color: #24292e;">js</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">n tamperlab
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-445"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-443">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-444'
	>
	As shown in the script&#8217;s output, we successfully bypass the check even though it resides within JNI code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-448"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-446"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-447">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_6.webp"
					class="image__img block-media__image-img"
					alt="Frida Interceptor.attach output showing successful override of CheckSuBinaryNative() return value to JNI_FALSE, bypassing native C/C++ SU binary detection"
										height="320"
															width="745"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-451"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-449">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-450'
	>
	Another clever approach is to hook the open() function instead of the entire native function implemented in the application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-454"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-452">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-453'
	>
	Since std::ifstream() ultimately invokes the open() system call, we can hook open() to intercept any attempt to access a binary whose path contains &#8220;su&#8221;. We can then substitute that path with a fake one to bypass the check.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-456"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Interceptor</span><span class="token">.</span><span class="token" style="color: #6f42c1;">attach</span><span class="token">(</span><span class="token" style="color: #24292e;">Module</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getExportByName</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">open</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    onEnter</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token"> </span><span class="token">(</span><span class="token">args</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">const</span><span class="token"> path </span><span class="token" style="color: #d73a49;">=</span><span class="token"> args</span><span class="token">[</span><span class="token" style="color: #005cc5;">0</span><span class="token">]</span><span class="token">.</span><span class="token" style="color: #6f42c1;">readUtf8String</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #24292e;">path</span><span class="token">.</span><span class="token" style="color: #6f42c1;">includes</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">su</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">[i] called open(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> path </span><span class="token" style="color: #d73a49;">+</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">);</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[i] App searching for the &#039;su&#039; binary</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[+] Overriding with random path value.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">const</span><span class="token"> newPath </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">Memory</span><span class="token">.</span><span class="token" style="color: #6f42c1;">allocUtf8String</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/dev/null</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            args</span><span class="token">[</span><span class="token" style="color: #005cc5;">0</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> newPath</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-459"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-457">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-458'
	>
	As shown in the image, this technique effectively bypasses native checks early by using the -f flag to hook before execution, unlike the -n flag, which attaches the hook while the process is already running.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-462"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-460"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-461">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_7.webp"
					class="image__img block-media__image-img"
					alt="Frida script hooking the open() system call to redirect any path containing &quot;su&quot; to /dev/null, bypassing native root detection before process execution using the -f flag"
										height="475"
															width="868"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-465"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-463">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-464'
	>
	Spoofing /proc/mounts</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-468"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-466">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-467'
	>
	Nowadays, many Android devices are commonly rooted using <a href="https://github.com/topjohnwu/Magisk">Magisk</a>, which comes with a variety of built-in features.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-471"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-469">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-470'
	>
	The /proc/mounts file contains a list of all currently mounted filesystems on the device. Additionally, when a device is rooted using Magisk, it modifies the boot image and mounts partitions dynamically by default, so you may find traces of Magisk there as well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-474"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-472"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-473">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_8.webp"
					class="image__img block-media__image-img"
					alt="Contents of /proc/mounts on a Magisk-rooted Android device showing magisk-related mount entries that reveal root status to detection mechanisms"
										height="171"
															width="1028"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-477"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-475">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-476'
	>
	An implementation to detect this might look like the following, where an application reads the contents of /proc/mounts in search of Magisk.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-479"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-html github-light" data-language="html" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">public static boolean isMagiskInMounts() {
</span></span><span class="line"><span class="token">  try {
</span></span><span class="line"><span class="token">    BufferedReader reader = new BufferedReader(new FileReader(&quot;/proc/mounts&quot;));
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    String line;
</span></span><span class="line"><span class="token">    while ((line = reader.readLine()) != null) {
</span></span><span class="line"><span class="token">      if (line.contains(&quot;magisk&quot;)        ||
</span></span><span class="line"><span class="token">          line.contains(&quot;/sbin/.magisk&quot;) ||
</span></span><span class="line"><span class="token">          line.contains(&quot;/dev/&quot;) &amp;&amp; line.contains(&quot;magisk&quot;)) {
</span></span><span class="line"><span class="token">        return true;
</span></span><span class="line"><span class="token">      }
</span></span><span class="line"><span class="token">    }
</span></span><span class="line"><span class="token">    reader.close();
</span></span><span class="line"><span class="token">  } catch (IOException e) {
</span></span><span class="line"><span class="token">    e.printStackTrace();
</span></span><span class="line"><span class="token">  }
</span></span><span class="line"><span class="token">  return false;
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-482"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-480">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-481'
	>
	To bypass this, we can create a script like the following, where we define a list of mounts that don’t contain Magisk traces or any other suspicious entries, for that matter.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-485"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-483">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-484'
	>
	The first interceptor hooks the open() system call to capture the file descriptor used when accessing /proc/mounts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-488"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-486">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-487'
	>
	The second interceptor hooks read(), checks if the file descriptor corresponds to /proc/mounts, ensures the content hasn’t already been spoofed (to prevent repeated modifications and potential crashes), and finally replaces the buffer with our fake mount data defined at the top.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-490"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">const</span><span class="token"> fake_mounts </span><span class="token" style="color: #d73a49;">=</span><span class="token"> `
</span></span><span class="line"><span class="token" style="color: #d73a49;">/</span><span class="token">dev</span><span class="token" style="color: #d73a49;">/</span><span class="token">block</span><span class="token" style="color: #d73a49;">/</span><span class="token">dm</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">8</span><span class="token"> </span><span class="token" style="color: #d73a49;">/</span><span class="token"> ext4 ro</span><span class="token">,</span><span class="token">seclabel</span><span class="token">,</span><span class="token">relatime </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">tmpfs </span><span class="token" style="color: #d73a49;">/</span><span class="token">dev tmpfs rw</span><span class="token">,</span><span class="token">seclabel</span><span class="token">,</span><span class="token">nosuid</span><span class="token">,</span><span class="token">relatime</span><span class="token">,</span><span class="token">size</span><span class="token" style="color: #d73a49;">=</span><span class="token">3896612k</span><span class="token">,</span><span class="token">nr_inodes</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">974153</span><span class="token">,</span><span class="token">mode</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">755</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">devpts </span><span class="token" style="color: #d73a49;">/</span><span class="token">dev</span><span class="token" style="color: #d73a49;">/</span><span class="token">pts devpts rw</span><span class="token">,</span><span class="token">seclabel</span><span class="token">,</span><span class="token">relatime</span><span class="token">,</span><span class="token">mode</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">600</span><span class="token">,</span><span class="token">ptmxmode</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">000</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">proc </span><span class="token" style="color: #d73a49;">/</span><span class="token">proc proc rw</span><span class="token">,</span><span class="token">relatime</span><span class="token">,</span><span class="token">gid</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">3009</span><span class="token">,</span><span class="token">hidepid</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">2</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">sysfs </span><span class="token" style="color: #d73a49;">/</span><span class="token">sys sysfs rw</span><span class="token">,</span><span class="token">seclabel</span><span class="token">,</span><span class="token">relatime </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">selinuxfs </span><span class="token" style="color: #d73a49;">/</span><span class="token">sys</span><span class="token" style="color: #d73a49;">/</span><span class="token">fs</span><span class="token" style="color: #d73a49;">/</span><span class="token">selinux selinuxfs rw</span><span class="token">,</span><span class="token">relatime </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">tmpfs </span><span class="token" style="color: #d73a49;">/</span><span class="token">mnt tmpfs rw</span><span class="token">,</span><span class="token">seclabel</span><span class="token">,</span><span class="token">nosuid</span><span class="token">,</span><span class="token">nodev</span><span class="token">,</span><span class="token">noexec</span><span class="token">,</span><span class="token">relatime</span><span class="token">,</span><span class="token">size</span><span class="token" style="color: #d73a49;">=</span><span class="token">3896612k</span><span class="token">,</span><span class="token">nr_inodes</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">974153</span><span class="token">,</span><span class="token">mode</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">755</span><span class="token">,</span><span class="token">gid</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">1000</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">tmpfs </span><span class="token" style="color: #d73a49;">/</span><span class="token">mnt</span><span class="token" style="color: #d73a49;">/</span><span class="token">installer tmpfs rw</span><span class="token">,</span><span class="token">seclabel</span><span class="token">,</span><span class="token">nosuid</span><span class="token">,</span><span class="token">nodev</span><span class="token">,</span><span class="token">noexec</span><span class="token">,</span><span class="token">relatime</span><span class="token">,</span><span class="token">size</span><span class="token" style="color: #d73a49;">=</span><span class="token">3896612k</span><span class="token">,</span><span class="token">nr_inodes</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">974153</span><span class="token">,</span><span class="token">mode</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">755</span><span class="token">,</span><span class="token">gid</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">1000</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">`</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">const</span><span class="token"> fakeMountBuffer </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">Memory</span><span class="token">.</span><span class="token" style="color: #6f42c1;">allocUtf8String</span><span class="token">(</span><span class="token">fake_mounts</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">let fakeMountFds </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">new</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Set</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">let hasSpoofed </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">Interceptor</span><span class="token">.</span><span class="token" style="color: #6f42c1;">attach</span><span class="token">(</span><span class="token" style="color: #24292e;">Module</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getExportByName</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">open</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    onEnter</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">args</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">path</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">Memory</span><span class="token">.</span><span class="token" style="color: #6f42c1;">readUtf8String</span><span class="token">(</span><span class="token">args</span><span class="token">[</span><span class="token" style="color: #005cc5;">0</span><span class="token">]</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    onLeave</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">retval</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">path</span><span class="token"> </span><span class="token" style="color: #d73a49;">===</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/proc/mounts</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">[i] /proc/mounts opened -&gt; file descriptor:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">fakeMountFds</span><span class="token">.</span><span class="token" style="color: #6f42c1;">add</span><span class="token">(</span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">Interceptor</span><span class="token">.</span><span class="token" style="color: #6f42c1;">attach</span><span class="token">(</span><span class="token" style="color: #24292e;">Module</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getExportByName</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">read</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    onEnter</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">args</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">fd</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> args</span><span class="token">[</span><span class="token" style="color: #005cc5;">0</span><span class="token">]</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">buf</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> args</span><span class="token">[</span><span class="token" style="color: #005cc5;">1</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">count</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> args</span><span class="token">[</span><span class="token" style="color: #005cc5;">2</span><span class="token">]</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    onLeave</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">retval</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #24292e;">fakeMountFds</span><span class="token">.</span><span class="token" style="color: #6f42c1;">has</span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">fd</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #d73a49;">!</span><span class="token">hasSpoofed</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">const</span><span class="token"> length </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">fake_mounts</span><span class="token">.</span><span class="token" style="color: #24292e;">length</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token">length </span><span class="token" style="color: #d73a49;">&lt;=</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">count</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                    hasSpoofed </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[+] Spoofing read() from /proc/mounts with fake one.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #24292e;">Memory</span><span class="token">.</span><span class="token" style="color: #6f42c1;">copy</span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">buf</span><span class="token">,</span><span class="token"> fakeMountBuffer</span><span class="token">,</span><span class="token"> length</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">replace</span><span class="token">(</span><span class="token">length</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[-] Buffer too small to spoof.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[+] /proc/mounts already spoofed, continuing...</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">replace</span><span class="token">(</span><span class="token" style="color: #005cc5;">0</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-493"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-491">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-492'
	>
	By running the hook, we successfully spoof the contents of /proc/mounts with our fake data, effectively bypassing the detection check.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-496"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-494"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-495">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_9.webp"
					class="image__img block-media__image-img"
					alt="Frida script output confirming successful spoofing of /proc/mounts read() call with clean fake mount data, bypassing Magisk detection"
										height="446"
															width="982"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-499"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-497">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-498'
	>
	It’s important to note that these techniques can be implemented and bypassed in various ways. Consequently, multiple solutions and countermeasures exist to address them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-502"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-500">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-501'
	>
	Anti-Hooking Protections</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-505"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-503">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-504'
	>
	Hooking is a powerful technique used during mobile penetration tests because it allows intercepting, modifying, and monitoring an application’s behavior at runtime. It provides direct access to function calls, arguments, return values, and the internal logic of methods.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-508"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-506">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-507'
	>
	To perform such attacks, <a href="https://github.com/frida/frida">Frida</a> is a widely used tool that enables pentesters and attackers to bypass security controls or extract potentially sensitive data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-511"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-509">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-510'
	>
	Frida Port Detection</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-514"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-512">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-513'
	>
	A common way to detect Frida is by checking for open frida-server ports, since Frida communicates using WebSockets. Simple checks often look for ports like 27042 or 27043, which are the default ports used by Frida.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-517"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-515">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-516'
	>
	Such checks can be easily bypassed by simply starting the Frida server on a different port using the following command.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-519"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">.</span><span class="token" style="color: #d73a49;">/</span><span class="token">frida</span><span class="token" style="color: #d73a49;">-</span><span class="token">server</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">16.5</span><span class="token">.</span><span class="token" style="color: #b31d28;font-style: italic;">9</span><span class="token" style="color: #d73a49;">-</span><span class="token">android</span><span class="token" style="color: #d73a49;">-</span><span class="token">arm64 </span><span class="token" style="color: #d73a49;">-</span><span class="token">l </span><span class="token" style="color: #005cc5;">0.0</span><span class="token">.</span><span class="token">0</span><span class="token">.</span><span class="token">0</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #005cc5;">1337</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-522"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-520">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-521'
	>
	A more advanced detection method involves scanning all ports by sending specific HTTP requests and checking for a 101 Switching Protocols response, which indicates the presence of a Frida server.An example of such native code would involve sending a WebSocket upgrade request to every open port on the device. If the response contains 101 Switching Protocols, it confirms that a Frida server has been successfully detected.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-524"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">for</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #d73a49;">int</span><span class="token"> </span><span class="token" style="color: #24292e;">i</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">;</span><span class="token"> i </span><span class="token" style="color: #d73a49;">&lt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">65535</span><span class="token">;</span><span class="token"> i</span><span class="token" style="color: #d73a49;">++</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #6f42c1;">connect</span><span class="token">(</span><span class="token">sock</span><span class="token">,</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #d73a49;">const</span><span class="token"> struct sockaddr</span><span class="token" style="color: #d73a49;">*</span><span class="token">)</span><span class="token" style="color: #d73a49;">&amp;</span><span class="token">addr</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">sizeof</span><span class="token">(</span><span class="token">addr</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">==</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">snprintf</span><span class="token">(</span><span class="token">req</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">sizeof</span><span class="token">(</span><span class="token">req</span><span class="token">)</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">GET /ws HTTP/1.1</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Host: %s:%d</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Upgrade: websocket</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Connection: Upgrade</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Sec-WebSocket-Key: CpxD2C5REVLHvsUC9YAoqg==</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Sec-WebSocket-Version: 13</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">User-Agent: Frida</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">                 </span><span class="token" style="color: #6f42c1;">inet_ntoa</span><span class="token">(</span><span class="token" style="color: #24292e;">addr</span><span class="token">.</span><span class="token" style="color: #24292e;">sin_addr</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ntohs</span><span class="token">(</span><span class="token" style="color: #24292e;">addr</span><span class="token">.</span><span class="token" style="color: #24292e;">sin_port</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">write</span><span class="token">(</span><span class="token">sock</span><span class="token">,</span><span class="token"> req</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">strlen</span><span class="token">(</span><span class="token">req</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        ssize_t bytes_read </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #6f42c1;">read</span><span class="token">(</span><span class="token">sock</span><span class="token">,</span><span class="token"> res</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">sizeof</span><span class="token">(</span><span class="token">res</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token">bytes_read </span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                res</span><span class="token">[</span><span class="token">bytes_read</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #005cc5;">\0</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #6f42c1;">strstr</span><span class="token">(</span><span class="token">res</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">101 Switching Protocols</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #6f42c1;">close</span><span class="token">(</span><span class="token">sock</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">return</span><span class="token"> JNI_TRUE</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-527"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-525">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-526'
	>
	This check can be bypassed by hooking the read() calls and inspecting the buffer content after the call completes. If the buffer contains 101 Switching Protocols, indicating a Frida server query, we can modify the response to something benign such as HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n to evade detection.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-529"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Interceptor</span><span class="token">.</span><span class="token" style="color: #6f42c1;">attach</span><span class="token">(</span><span class="token" style="color: #24292e;">Module</span><span class="token">.</span><span class="token" style="color: #6f42c1;">findExportByName</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">read</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    onEnter</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">args</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">buffer</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> args</span><span class="token">[</span><span class="token" style="color: #005cc5;">1</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">size</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> args</span><span class="token">[</span><span class="token" style="color: #005cc5;">2</span><span class="token">]</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">curr_retval</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    onLeave</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">function</span><span class="token">(</span><span class="token">retval</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">curr_retval</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">toInt32</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">curr_retval</span><span class="token"> </span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #24292e;">response</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">buffer</span><span class="token">.</span><span class="token" style="color: #6f42c1;">readCString</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #24292e;">response</span><span class="token">.</span><span class="token" style="color: #6f42c1;">includes</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">101 Switching Protocols</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">[i] Application detected Frida server via WebSocket</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">console</span><span class="token">.</span><span class="token" style="color: #6f42c1;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\t</span><span class="token" style="color: #032f62;">[+] Modifying the WebSocket response</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #24292e;">modifiedResponse</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">HTTP/1.1 200 OK</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">Content-Length: 0</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #005cc5;">\r</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">this</span><span class="token">.</span><span class="token" style="color: #24292e;">buffer</span><span class="token">.</span><span class="token" style="color: #6f42c1;">writeUtf8String</span><span class="token">(</span><span class="token">modifiedResponse</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">retval</span><span class="token">.</span><span class="token" style="color: #6f42c1;">replace</span><span class="token">(</span><span class="token" style="color: #24292e;">modifiedResponse</span><span class="token">.</span><span class="token" style="color: #24292e;">length</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-532"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-530">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-531'
	>
	As demonstrated, once the hook is executed, the check is successfully bypassed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-535"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-533"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-534">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_10.webp"
					class="image__img block-media__image-img"
					alt="Frida read() hook modifying WebSocket 101 Switching Protocols response to HTTP 200 OK, successfully bypassing Frida port detection across all 65535 ports"
										height="313"
															width="755"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-538"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-536">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-537'
	>
	Frida Threads Detection</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-541"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-539">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-540'
	>
	In Linux-based environments (including Android), each process has a task directory located at /proc/self/task, containing a subdirectory for each thread within the process. Each of these subdirectories includes a comm file that holds the name of the corresponding thread.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-544"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-542">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-543'
	>
	When Frida is injected into a process, it typically creates several threads for its internal operations. These threads often have distinctive names such as frida, gum-js-loop, gmain, gdbus or some other which can be used to detect Frida&#8217;s presence.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-547"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-545">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-546'
	>
	To better understand this, we can run the following command on the device to retrieve the names of all threads for a specified process.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-549"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">PPID</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #6f42c1;">$</span><span class="token">(</span><span class="token">pidof </span><span class="token" style="color: #24292e;">com</span><span class="token">.</span><span class="token" style="color: #24292e;">hacking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">)</span><span class="token">;</span><span class="token"> </span><span class="token" style="color: #d73a49;">for</span><span class="token"> i in </span><span class="token" style="color: #d73a49;">/</span><span class="token">proc</span><span class="token" style="color: #d73a49;">/</span><span class="token">$PPID</span><span class="token" style="color: #d73a49;">/</span><span class="token">task</span><span class="token" style="color: #6a737d;">/*</span><span class="token" style="color: #6a737d;">; do cat &quot;$i/comm&quot; 2&gt;/dev/null; done
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-552"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-550">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-551'
	>
	As shown in the following snippet, this is the output of the thread list when no Frida hooks are active.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-554"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">cking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">Signal</span><span class="token"> </span><span class="token" style="color: #24292e;">Catcher</span><span class="token">
</span></span><span class="line"><span class="token">perfetto_hprof_
</span></span><span class="line"><span class="token">ADB</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #24292e;">JDWP</span><span class="token"> </span><span class="token" style="color: #24292e;">Connec</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">Jit</span><span class="token"> thread pool
</span></span><span class="line"><span class="token">mali</span><span class="token" style="color: #d73a49;">-</span><span class="token">utility</span><span class="token" style="color: #d73a49;">-</span><span class="token">wo
</span></span><span class="line"><span class="token">mali</span><span class="token" style="color: #d73a49;">-</span><span class="token">cmar</span><span class="token" style="color: #d73a49;">-</span><span class="token">backe
</span></span><span class="line"><span class="token">ged</span><span class="token" style="color: #d73a49;">-</span><span class="token">swd
</span></span><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-557"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-555">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-556'
	>
	When a Frida hook is applied to the process, threads named gmain and gdbus appear both associated with Frida’s runtime. This allows us to detect Frida based on the presence of these thread names.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-559"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">cking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">
</span></span><span class="line"><span class="token">perfetto_hprof_
</span></span><span class="line"><span class="token">ADB</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #24292e;">JDWP</span><span class="token"> </span><span class="token" style="color: #24292e;">Connec</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">Jit</span><span class="token"> thread pool
</span></span><span class="line"><span class="token">mali</span><span class="token" style="color: #d73a49;">-</span><span class="token">cmar</span><span class="token" style="color: #d73a49;">-</span><span class="token">backe
</span></span><span class="line"><span class="token" style="color: #24292e;">RenderThread</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">cking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">
</span></span><span class="line"><span class="token">gmain
</span></span><span class="line"><span class="token">gdbus
</span></span><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-562"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-560">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-561'
	>
	To detect this, we can use C++ code like the following, which loops through each comm file in the /proc/self/task directory to retrieve thread names and checks them against a list of common thread names used by Frida.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-564"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token" style="color: #005cc5;">SNIP</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">DIR</span><span class="token"> </span><span class="token" style="color: #d73a49;">*</span><span class="token" style="color: #005cc5;">dir</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">opendir</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/proc/self/task</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token" style="color: #005cc5;">SNIP</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">struct</span><span class="token"> </span><span class="token" style="color: #005cc5;">dirent</span><span class="token"> </span><span class="token" style="color: #d73a49;">*</span><span class="token" style="color: #005cc5;">entry</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">char</span><span class="token"> </span><span class="token" style="color: #005cc5;">path</span><span class="token">[</span><span class="token" style="color: #005cc5;">PATH_MAX</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">char</span><span class="token"> </span><span class="token" style="color: #005cc5;">comm</span><span class="token">[</span><span class="token" style="color: #005cc5;">256</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">while</span><span class="token"> </span><span class="token">(</span><span class="token">(</span><span class="token" style="color: #005cc5;">entry</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">readdir</span><span class="token">(</span><span class="token" style="color: #005cc5;">dir</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">NULL</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token" style="color: #005cc5;">SNIP</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">snprintf</span><span class="token">(</span><span class="token" style="color: #005cc5;">path</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">sizeof</span><span class="token">(</span><span class="token" style="color: #005cc5;">path</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/proc/self/task/%s/comm</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">entry</span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token" style="color: #24292e;">d_name</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token" style="color: #005cc5;">SNIP</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">fgets</span><span class="token">(</span><span class="token" style="color: #005cc5;">comm</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">sizeof</span><span class="token">(</span><span class="token" style="color: #005cc5;">comm</span><span class="token">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">fp</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">NULL</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #005cc5;">comm</span><span class="token">[</span><span class="token" style="color: #005cc5;">strcspn</span><span class="token">(</span><span class="token" style="color: #005cc5;">comm</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;">\n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">strstr</span><span class="token">(</span><span class="token" style="color: #005cc5;">comm</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">frida</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">||</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">strstr</span><span class="token">(</span><span class="token" style="color: #005cc5;">comm</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">gum</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">   </span><span class="token" style="color: #d73a49;">||</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">strstr</span><span class="token">(</span><span class="token" style="color: #005cc5;">comm</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">gmain</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">fclose</span><span class="token">(</span><span class="token" style="color: #005cc5;">fp</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">closedir</span><span class="token">(</span><span class="token" style="color: #005cc5;">dir</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">JNI_TRUE</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">fclose</span><span class="token">(</span><span class="token" style="color: #005cc5;">fp</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">closedir</span><span class="token">(</span><span class="token" style="color: #005cc5;">dir</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">JNI_FALSE</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token" style="color: #005cc5;">SNIP</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-567"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-565">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-566'
	>
	One intriguing approach to evade detection is to patch the entire frida-server binary by replacing all occurrences of strings like gmain. By searching for gmain in Ghidra, we can observe the following results.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-570"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-568"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-569">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_11.webp"
					class="image__img block-media__image-img"
					alt="Ghidra search results showing multiple occurrences of the &quot;gmain&quot; string inside the frida-server binary, used for Frida thread name detection"
										height="522"
															width="917"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-573"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-571">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-572'
	>
	By selecting one of the instances, we can examine the disassembled code to pinpoint its exact location.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-576"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-574"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-575">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_12.webp"
					class="image__img block-media__image-img"
					alt="Ghidra disassembly view showing exact memory location of the gmain string in the frida-server binary for targeted patching"
										height="305"
															width="848"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-579"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-577">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-578'
	>
	We can now use Ghidra’s built-in hex editor to modify these strings, replacing gmain with another string, such as hackr.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-582"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-580"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-581">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_13.webp"
					class="image__img block-media__image-img"
					alt="Ghidra hex editor view showing gmain string being replaced with hackr to rename Frida&#039;s internal thread and evade thread-name-based detection"
										height="247"
															width="933"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-585"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-583">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-584'
	>
	After injecting the Frida hook, we can see that we have successfully bypassed the detection, as it no longer identifies Frida’s threads.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-588"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-586"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-587">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_14.webp"
					class="image__img block-media__image-img"
					alt="Frida injection output after frida-server binary patch showing Frida threads no longer detected, with renamed thread appearing as hackr instead of gmain"
										height="310"
															width="478"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-591"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-589">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-590'
	>
	If we loop through the thread names again for the application we are attacking, we can see that it now successfully contains the hackr thread name.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-593"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">cking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">ReferenceQueueD</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">FinalizerDaemon</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">FinalizerWatchd</span><span class="token">
</span></span><span class="line"><span class="token">binder</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #005cc5;">7261_1</span><span class="token">
</span></span><span class="line"><span class="token">binder</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #005cc5;">7261_2</span><span class="token">
</span></span><span class="line"><span class="token">hackr
</span></span><span class="line"><span class="token">gdbus
</span></span><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-596"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-594">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-595'
	>
	Of course, there are other detectable strings, but this simple example demonstrates one way to bypass detection by directly patching the frida-server binary yourself. This way you could build an entirely different frida-server to avoid detections or modify the original source code as well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-599"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-597">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-598'
	>
	Anti-Debug Protections</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-602"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-600">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-601'
	>
	Anti-debug protections are another way to protect your Android application from reverse engineering. These mechanisms aim to detect or prevent debugging attempts, stopping attackers from stepping through the app’s code instruction by instruction to understand its internal logic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-605"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-603">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-604'
	>
	Like most security measures, anti-debug mechanisms can also be bypassed using Frida hooks. However, I want to show you how you can defeat these protections using a debugger itself.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-608"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-606">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-607'
	>
	Defeating Anti-Debug using Debugger</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-611"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-609">
	<h4	class='typography typography--size-24-text js-typography block-typography__typography'
	data-id='es-610'
	>
	isDebuggerConnected()</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-614"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-612">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-613'
	>
	This is a simple, ready-made function that checks if a debugger is connected to the application. It returns true if a debugger is detected, otherwise, it returns false.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-617"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-615">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-616'
	>
	Implementing such a function is straightforward, and you can call it as follows:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-619"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Debug</span><span class="token">.</span><span class="token" style="color: #6f42c1;">isDebuggerConnected</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-622"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-620">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-621'
	>
	To use the debugger and bypass this check, we can utilize JADX’s integrated debugger. Before launching it, ensure the application is already running.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-625"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-623">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-624'
	>
	Another way to start an application is by using the following ADB command, which will launch the app but pause and wait for the debugger to attach.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-627"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">adb shell am set</span><span class="token" style="color: #d73a49;">-</span><span class="token">debug</span><span class="token" style="color: #d73a49;">-</span><span class="token">app </span><span class="token" style="color: #d73a49;">-</span><span class="token">w </span><span class="token" style="color: #24292e;">com</span><span class="token">.</span><span class="token" style="color: #24292e;">hacking</span><span class="token">.</span><span class="token" style="color: #24292e;">tamperlab</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-630"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-628">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-629'
	>
	As shown, when you launch the application, it will display a message indicating that it is waiting for a debugger.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-633"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-631"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-632">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_15.webp"
					class="image__img block-media__image-img"
					alt="Android device screen showing &quot;Waiting For Debugger&quot; dialog after launching TamperLab with ADB debug flag, pausing app execution until debugger attaches"
										height="214"
															width="355"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-636"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-634">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-635'
	>
	In my case, it doesn’t work, but I can open the application without it waiting for the debugger. However, your application might require this behavior, so it’s important to test both methods.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-639"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-637">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-638'
	>
	Additionally, whenever you’re done or close the application, make sure to run the following command to remove the app from waiting for a debugger.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-641"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">adb shell am clear</span><span class="token" style="color: #d73a49;">-</span><span class="token">debug</span><span class="token" style="color: #d73a49;">-</span><span class="token">app
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-644"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-642">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-643'
	>
	Once ready, you can open JADX and load the APK file of the target application. You can also pull the APK from your device using ADB.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-647"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-645">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-646'
	>
	Once loaded into JADX, select the green bug icon, which opens a dialog prompting you to choose the application to debug along with its process ID.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-650"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-648"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-649">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_16.webp"
					class="image__img block-media__image-img"
					alt="JADX integrated debugger showing process selection dialog for com.hacking.tamperlab to attach debugger to the running TamperLab application"
										height="255"
															width="864"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-653"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-651">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-652'
	>
	After the debugger attaches, the application’s execution is automatically paused inside the MainActivity. You can then press the green play button to continue running the application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-656"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-654"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-655">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_17.webp"
					class="image__img block-media__image-img"
					alt="JADX debugger paused at MainActivity entry point after attaching, with green play button ready to resume application execution"
										height="377"
															width="968"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-659"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-657">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-658'
	>
	Once you find the correct position to set a breakpoint, you can do so by pressing the F2 key. For this example, I set the breakpoint exactly where the isDebuggerConnected() function is called.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-662"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-660"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-661">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_18.webp"
					class="image__img block-media__image-img"
					alt="JADX debugger showing breakpoint set on invoke-static opcode calling isDebuggerConnected(), with v0 register visible in the debug variables panel"
										height="239"
															width="957"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-665"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-663">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-664'
	>
	The following instruction essentially calls the isDebuggerConnected() function using the invoke-static opcode.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-667"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">invoke</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #d73a49;">static</span><span class="token"> </span><span class="token">{</span><span class="token">}</span><span class="token">,</span><span class="token"> Landroid</span><span class="token" style="color: #d73a49;">/</span><span class="token">os</span><span class="token" style="color: #d73a49;">/</span><span class="token">Debug</span><span class="token">;</span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token" style="color: #6f42c1;">isDebuggerConnected</span><span class="token">(</span><span class="token">)</span><span class="token">Z # method</span><span class="token">@</span><span class="token" style="color: #d73a49;">0008</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-670"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-668">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-669'
	>
	Then, the move-result instruction moves the return value of the function (either true or false) into the v0 register.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-672"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-html github-light" data-language="html" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">move-result v0
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-675"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-673">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-674'
	>
	By stepping over these two instructions, we can observe that the v0 register contains the value 1, indicating that a debugger has been detected.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-678"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-676"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-677">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_19.webp"
					class="image__img block-media__image-img"
					alt="JADX debugger showing v0 register containing value 1 (true) after move-result instruction, confirming debugger was detected by isDebuggerConnected()"
										height="324"
															width="1129"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-681"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-679">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-680'
	>
	To bypass this check, we can simply set the value to 0 using the debugger, as shown below:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-684"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-682"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-683">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_20.webp"
					class="image__img block-media__image-img"
					alt="JADX debugger view showing v0 register value manually overridden to 0 (false) to bypass isDebuggerConnected() check during live debugging session"
										height="302"
															width="1139"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-687"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-685">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-686'
	>
	Continuing the application’s execution, we successfully bypass the check by manipulating the variables during debugging.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-690"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-688"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-689">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_21.webp"
					class="image__img block-media__image-img"
					alt="TamperLab app showing green checkmark after successfully bypassing isDebuggerConnected() anti-debug protection by manipulating register value in JADX debugger"
										height="261"
															width="344"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-693"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-691">
	<h4	class='typography typography--size-24-text js-typography block-typography__typography'
	data-id='es-692'
	>
	Detection via USB &amp; ADB</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-696"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-694">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-695'
	>
	Another interesting way to detect debugging is by checking if the device is connected via USB with ADB enabled. While this isn’t a direct debugger detection method, it remains a useful check nonetheless.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-699"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-697">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-698'
	>
	A simple implementation might look like the following, where the app dynamically listens for the USB_STATE broadcast and parses the connected and adb boolean extras from the received intent.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-701"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">IntentFilter</span><span class="token"> </span><span class="token" style="color: #24292e;">filter</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">new</span><span class="token"> </span><span class="token" style="color: #6f42c1;">IntentFilter</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">android.hardware.usb.action.USB_STATE</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">BroadcastReceiver</span><span class="token"> </span><span class="token" style="color: #24292e;">usbReceiver</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">new</span><span class="token"> </span><span class="token" style="color: #6f42c1;">BroadcastReceiver</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">@</span><span class="token" style="color: #d73a49;">Override</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">void</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onReceive</span><span class="token">(</span><span class="token" style="color: #24292e;">Context</span><span class="token"> </span><span class="token" style="color: #e36209;">ctx</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #24292e;">Intent</span><span class="token"> </span><span class="token" style="color: #e36209;">intent</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">boolean</span><span class="token"> </span><span class="token" style="color: #24292e;">connected</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">intent</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getBooleanExtra</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">connected</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">boolean</span><span class="token"> </span><span class="token" style="color: #24292e;">adbEnabled</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">intent</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getBooleanExtra</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">adb</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">callback</span><span class="token">.</span><span class="token" style="color: #6f42c1;">accept</span><span class="token">(</span><span class="token">connected </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> adbEnabled</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #24292e;">ctx</span><span class="token">.</span><span class="token" style="color: #6f42c1;">unregisterReceiver</span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">context</span><span class="token">.</span><span class="token" style="color: #6f42c1;">registerReceiver</span><span class="token">(</span><span class="token">usbReceiver</span><span class="token">,</span><span class="token"> filter</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #24292e;">Intent</span><span class="token"> </span><span class="token" style="color: #24292e;">sticky</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">context</span><span class="token">.</span><span class="token" style="color: #6f42c1;">registerReceiver</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">,</span><span class="token"> filter</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token">sticky </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #24292e;">usbReceiver</span><span class="token">.</span><span class="token" style="color: #6f42c1;">onReceive</span><span class="token">(</span><span class="token">context</span><span class="token">,</span><span class="token"> sticky</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">[</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token" style="color: #24292e;">SNIP</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-704"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-702">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-703'
	>
	We can also bypass this check by using the debugger to place breakpoints at the appropriate locations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-707"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-705">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-706'
	>
	In this case, I set a breakpoint on the if-eqz instructions, which checks whether the values in registers v0 and v2 are equal to zero. These registers correspond to the connected and adbEnabled flags.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-710"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-708">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-709'
	>
	When the breakpoint is hit, we observe that both values are set to 1 (true), indicating that USB is connected and ADB is enabled.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-713"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-711"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-712">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/03/image_22.webp"
					class="image__img block-media__image-img"
					alt="JADX debugger breakpoint showing if-eqz instructions with v0 (connected=1) and v2 (adbEnabled=1) registers, detecting USB connection with ADB enabled"
										height="501"
															width="1088"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-716"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-714">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-715'
	>
	We can now simply set these two values to 0 (false), causing the check to fail and allowing the app to continue execution.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-719"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-717">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-718'
	>
	Conclusion</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-722"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-720">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-721'
	>
	We have explored several common anti-root, anti-hook, and anti-debug techniques and demonstrated how each can ultimately be bypassed. However, it is important to recognize that these protections still play a critical role in Android security.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-725"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-723">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-724'
	>
	No protection is entirely foolproof. Given enough time and the right tools, a determined attacker can often find a way around most defenses. However, the goal of these mechanisms isn’t to create an unbreakable application, but rather to increase the complexity of attacks. This raises the time, effort, and skill required for an attacker to compromise the application, which can deter casual attackers and slow down more advanced ones.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-728"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-726">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-727'
	>
	In short, while these security checks can be bypassed, they remain a valuable part of a defense-in-depth strategy. Labs like TamperLab that we have created, provide a practical environment where you can practice implementing these detection mechanisms and learn how to bypass them. It’s about making it hard enough that breaking the security is no longer worth the effort.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-731"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-729">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-730'
	>
	At Infinum, we help you stay ahead with tailored cybersecurity services, including <a href="https://infinum.com/cybersecurity/penetration-testing/" id="https://infinum.com/cybersecurity/penetration-testing/">penetration testing</a> and <a href="https://infinum.com/cybersecurity/red-teaming/" id="https://infinum.com/cybersecurity/red-teaming/">security assessments</a>. Whether launching new products or protecting existing ones, we identify weaknesses before attackers do so you can focus on what matters. Learn more about how we keep your digital world secure on our <a href="https://infinum.com/cybersecurity/">cybersecurity page</a>.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/understanding-defeating-android-protections/">Understanding &amp; Defeating Android Protections</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>19276208https://infinum.com/uploads/2026/03/ai-generated-code.webp</url>
				</image>
				<title>Is AI-Generated Code Secure? What Business Leaders Need to Know About AI and Application Security</title>
				<link>https://infinum.com/blog/ai-generated-code-security-risks/</link>
				<pubDate>Fri, 06 Mar 2026 13:47:45 +0000</pubDate>
				<dc:creator>Hrvoje Filaković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=19276208</guid>
				<description>
					<![CDATA[<p>We asked AI to build three web apps with different levels of security guidance, then tried to break them. Here’s what we found.</p>
<p>The post <a href="https://infinum.com/blog/ai-generated-code-security-risks/">Is AI-Generated Code Secure? What Business Leaders Need to Know About AI and Application Security</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-961"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-734">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-737"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-735">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-736'
	>
	<strong>AI is changing how software gets built: faster timelines, leaner teams, fewer blockers. But does all that speed come at a cost? We put AI to the test in a real-world security experiment, and what we learned should matter to anyone leading modern product, platform, or tech teams.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-740"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-738">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-739'
	>
	According to Collins Dictionary, <em>vibe coding</em> is officially <a href="https://www.theguardian.com/technology/2025/nov/06/vibe-coding-collins-dictionary-word-of-the-year-2025">the word of the year</a> – and if you’ve spent literally <em>any</em> time around engineering teams lately, that probably doesn’t surprise you.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-743"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-741">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-742'
	>
	Obviously, it’s catching on fast. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-746"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-744">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-745'
	>
	Microsoft recently shared that around <a href="https://www.theverge.com/news/658584/up-to-30-percent-of-some-microsoft-code-is-now-written-by-ai">30% of the code in some of its repositories is now AI-generated</a>. This shift is one of the defining cybersecurity risks of 2026 — our <a href="https://infinum.com/blog/cybersecurity-trends-2026/">cybersecurity trends overview</a> covers the trade-off between vibe coding and security in depth. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-749"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-747">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-748'
	>
	At <a href="https://infinum.com/">Infinum</a>, we see this trend up close, both in internal experimentation and in conversations with clients who are increasingly curious about AI-assisted development. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-752"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-750">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-751'
	>
	The appeal is clear: development is faster, <a href="https://infinum.com/blog/ai-automation/" id="https://infinum.com/blog/ai-automation/">prototypes turn into products at record speed</a>, and teams feel confident shipping. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-755"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-753">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-754'
	>
	But is that confidence earned? We decided to find out.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-758"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-756">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-757'
	>
	<strong>Security doesn’t work on vibes</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-761"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-759">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-760'
	>
	A growing belief is quietly taking hold in many teams:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-764"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-762">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-763'
	>
	<em>“If I tell the AI to make it secure, it probably will.”</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-767"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-765">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-766'
	>
	That assumption is understandable because AI is very good at reproducing patterns that <em>look</em> correct. When prompted, it can generate code that resembles common security practices and includes familiar terminology, giving the impression that risk has been addressed. But is it, really?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-770"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-768">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-769'
	>
	Instead of debating, our cybersecurity engineer designed a simple, hands-on experiment.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-773"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-771">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-772'
	>
	He asked AI to build apps with varying levels of security guidance, from none to OWASP-level detail, and then he tried to break them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-776"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-774">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-775'
	>
	We didn’t want to test whether AI could write code. We know it can.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-778"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-777'
	>
	<strong>Likewise, the goal wasn’t to assess if AI builds insecure apps by default. We wanted to test whether adding “make it secure” to your prompt is enough to stop vulnerabilities – and how that changes as you get more specific.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-781"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-779">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-780'
	>
	Let’s see the results.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-784"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-782">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-783'
	>
	<strong>The apps we built (and broke)</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-787"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-785">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-786'
	>
	We asked AI to build three medium-complexity web applications, realistic enough to offer an attack surface, but not so complex that AI failed to build them. One app was generated with no security input at all, one with light guidance, and one with detailed, best-practice-driven instructions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-790"
	 data-animation-target='inner-items'>
		
			<div class="block-group" data-id=es-789>
	
<div
	class="wrapper"
	data-id="es-788"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			
<figure class="wp-block-table is-style-first-column-strong"><table class="has-fixed-layout"><thead><tr><th><strong>App</strong></th><th><strong>Security guidance</strong></th><th><strong>Security quality</strong></th><th><strong>Outcome</strong></th></tr></thead><tbody><tr><td>Simple Project Tracker &#8211; task and project manager for small teams</td><td>None</td><td>Poor</td><td>Multiple critical issues in input validation, design, and session handling, easily leading to worst-case exploitation scenarios. Users could make themselves admins.&nbsp;</td></tr><tr><td>Project Resource Hub &#8211; internal portal for sharing documents and guides</td><td>Light</td><td>Mixed</td><td>Critical issues reduced, but several vulnerabilities remain that could still expose sensitive information, such as SSRF and malicious file uploads.</td></tr><tr><td>Niche Vault &#8211; hobbyist catalog site for personal collections</td><td>Detailed &amp; <a href="https://infinum.com/blog/owasp-top-10-mobile/" id="https://infinum.com/blog/owasp-top-10-mobile/">OWASP-based</a></td><td>Better, but insufficient</td><td>Significantly fewer vulnerabilities; none severe, but still issues that could pose risks over time. Missed CSV injection, rate-limiting, and open redirects.</td></tr></tbody></table></figure>
		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-793"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-791">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-792'
	>
	Turns out, not even specific prompts are enough to build applications that can survive real-world attacks.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-800"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-794"
	 href='https://infinum.com/blog/security-gaps-in-vibe-coded-applications/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<p	class='typography typography--size-36-text js-typography card-simple__heading'
	data-id='es-795'
	>
	<strong>Want to learn all technical details of the experiments, including exact prompts, a detailed overview of found issues, and our engineer’s conclusion? </strong></p>		</div>

		<p	class='typography typography--size-16-text-roman js-typography card-simple__paragraph'
	data-id='es-796'
	 id='es-794-paragraph'>
	Explore the complete overview of this experiment.</p><button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-797"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-798'
	>
	<strong><strong>Let’s get technical</strong></strong></div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-799'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-803"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-801">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-802'
	>
	<strong>What actually went wrong </strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-806"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-804">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-805'
	>
	Even with better prompts, the same kinds of security gaps kept popping up.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-809"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-807">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-808'
	>
	<span class='screen-reader-text'>AI didn’t forget libraries or miss syntax. It just couldn’t reason about how things might go wrong, and that’s where real-life threats were.</span><span aria-hidden='true'>AI didn’t forget libraries or miss syntax. </span></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-812"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-810">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-811'
	>
	<span class='screen-reader-text'>AI didn’t forget libraries or miss syntax. It just couldn’t reason about how things might go wrong, and that’s where real-life threats were.</span><span aria-hidden='true'>AI simply doesn&#8217;t understand cybersecurity, and it couldn’t reason about <em>how things might go wrong</em>, and that’s where real-life threats were.</span></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-815"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-813">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-814'
	>
	While we are aware that this is an experiment of a limited scope, it is still important to note recurring issues we recognized:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-819"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-816">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-817'
	>
	<strong>Trust in user input</strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-818'
	>
	AI simply trusted what users said about themselves. In multiple apps, user roles (such as admin) were accepted directly from client input, with no validation or enforcement. If someone claimed to be an admin, the system said: “Sure, sounds legit.” Just like that, admin access was self-serve.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-823"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-820">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-821'
	>
	<strong><strong><strong>Broken or missing access control</strong></strong></strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-822'
	>
	Even when roles were assigned correctly, features didn’t enforce them properly. There were no ownership checks, no context validation, no guardrails. Anyone logged in could view, modify, or delete other users’ data.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-827"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-824">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-825'
	>
	<strong><strong><strong><strong>Feature-level defenses, system-level blind spots</strong></strong></strong></strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-826'
	>
	AI knew to sanitize an input field, but it didn’t think about how that input might travel through the system. Security was applied in pieces, not as a pattern, which means defenses weren’t absent; they were just easy to step around. This fragmentation is also why <a href="https://infinum.com/blog/software-supply-chain-security/">software supply chain security</a> requires a systemic approach — the weakest link is rarely where you&#8217;re looking.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-831"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-828">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-829'
	>
	<strong><strong><strong><strong><strong>Reactive security instead of proactive thinking</strong></strong></strong></strong></strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-830'
	>
	The apps didn’t lack rate limiting, but rate limiting was only added to endpoints the prompt specifically called “sensitive.” In other words, if you want a feature to be secure, you have to explicitly tell the AI – every time.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-835"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-832">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-833'
	>
	<strong><strong><strong><strong><strong><strong>No imagination for abuse cases</strong></strong></strong></strong></strong></strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-834'
	>
	And this might be the most important insight of all: the AI assumed good-faith users. It never asked the question that is the foundation of real-world security: <em>What if someone does the wrong thing on purpose?</em><br />
</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-838"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-836">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-837'
	>
	In conclusion, the issues discovered weren’t bugs in the traditional sense. They were assumptions – that roles are respected, that the app can trust user input, that attackers won’t be creative.  </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-843"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-839">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-24 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-840'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-841'
	>
	<strong>Most of the problems were not broken locks, but doors that simply weren’t locked because AI assumed nobody would try them.</strong></p>
		<div class="blockquote__caption-wrap">
			<div	class='typography typography--size-12-text-roman js-typography blockquote__caption'
	data-id='es-842'
	>
	<strong>HRVOJE FILAKOVIĆ</strong>,<br>CYBERSECURITY ENGINEER</div>		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-846"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-844">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-845'
	>
	But attackers are creative, and they have all the time in the world to look for what you missed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-849"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-847">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-848'
	>
	<strong>Why this matters beyond the code</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-852"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-850">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-851'
	>
	Security is not just a dev problem. It&#8217;s a systems-thinking problem, and it affects every role involved in shipping software.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-855"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-853">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-854'
	>
	<strong><strong>For CTOs &amp; Heads of Engineering</strong></strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-858"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-856">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-857'
	>
	AI speeds things up, no question, but it can’t replace architectural thinking. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-861"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-859">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-860'
	>
	The biggest failures in these apps weren’t in the code; they were bad assumptions about how trust, roles, and permissions work. Even when AI adds security controls, it struggles to secure the system as a whole.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-864"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-862">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-863'
	>
	We’ve all recently witnessed this: in our <a href="https://infinum.com/blog/openclaw-moltbot-clawdbot-viral-ai-sidekick/">deep dive into OpenClaw (ex Moltbot)</a>, we explored what happens when AI sidekicks are given broad access with no guardrails. The takeaway? When AI has too much control, your data is very likely at risk. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-867"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-865">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-866'
	>
	Again, that’s an architectural one. And it’s still up to humans to get it right.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-870"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-868">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-869'
	>
	<strong>For Founders &amp; Execs</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-873"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-871">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-872'
	>
	All three apps worked. Some even looked secure. But they could still be exploited in serious ways, often through features that seemed harmless. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-876"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-874">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-875'
	>
	Remember this: AI gives a false sense of security. Without hands-on testing, issues like these show up only after damage is done. If you&#8217;re building with AI and need it to be secure from the start, our <a href="https://infinum.com/custom-ai-development-services/">custom AI development services</a> combine speed with security by design.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-879"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-877">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-878'
	>
	<strong>For Security Leaders</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-882"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-880">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-881'
	>
	The vulnerabilities we found didn’t have CVE numbers. They weren’t from outdated libraries or missing headers. They were logic and abuse-case failures – the exact kind of problems <a href="https://infinum.com/blog/why-penetration-testing-is-important/">automated scanners don’t catch</a>. Addressing these systematically through structured security governance, risk assessment, and compliance frameworks is exactly what <a href="https://infinum.com/governance-risk-compliance-services/">governance, risk, and compliance services</a> are designed to support.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-885"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-883">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-884'
	>
	Manual <a href="https://infinum.com/cybersecurity/penetration-testing/">penetration testing</a> still matters because it mirrors how attackers behave, not just what vulnerabilities exist – and AI-assisted code makes this more important, not less.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-888"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-886">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-887'
	>
	For <strong style="font-weight: bold">Developers</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-891"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-889">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-890'
	>
	AI can implement what you tell it, but it’s not a security expert. It won’t catch logic flaws, system-wide assumptions, or the creative misuse attackers are known for. For a practical look at how to work with AI coding assistants without sacrificing code quality, see our roundup of <a href="https://infinum.com/blog/ai-agency-ai-tools/">AI tools for development teams</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-894"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-892">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-893'
	>
	Writing secure apps still requires developer intuition, threat awareness, and curiosity about how features might be abused.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-896"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-895'
	>
	<strong><strong>The key takeaway: “Please make it secure” is not a security strategy. AI can help you build faster <em>only if you know exactly what to ask for</em>, and even then, it often misses the bigger picture. </strong></strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-899"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-897">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-898'
	>
	So, yes. AI-generated code can be secure, but it takes judgement, experience, and most importantly, testing.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-902"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-900">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-901'
	>
	<strong>What should you do now</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-905"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-903">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-904'
	>
	Use AI. Embrace the speed. Build more, experiment faster, prototype wildly. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-908"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-906">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-907'
	>
	But don’t confuse working code with secure code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-911"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-909">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-910'
	>
	<li><strong>Bring in experienced engineers.</strong> Secure software doesn’t just happen, it’s built intentionally. <a href="https://infinum.com/blog/ssdlc-application-security/">SSDLC practices are more essential than ever</a> when code is being generated at speed. For mobile developers in particular, intentional security means implementing runtime protections that resist reverse engineering — something we explore hands-on in our <a href="https://infinum.com/blog/understanding-defeating-android-protections/">guide to Android anti-root, anti-hook, and anti-debug mechanisms</a>. Before scaling AI-assisted development across your team, it helps to have a clear <a href="https://infinum.com/blog/ai-strategy/">AI strategy</a> — one that accounts for security, governance, and the right use cases from the start. </li><li><strong>Test like an attacker.</strong> <a href="https://infinum.com/blog/penetration-testing-steps/">Manual penetration testing</a> reveals what AI misses: the logic flaws, the edge cases, all the blind spots that open into serious vulnerabilities.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-914"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-912">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-913'
	>
	<strong>Why automated scanners won’t help</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-917"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-915">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-916'
	>
	Automated tools catch known and “low-hanging fruit” types of vulnerabilities. But issues discovered in this experiment weren’t in any vulnerability database, because they weren’t traditional bugs – they were incorrect assumptions about how systems would be used.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-919"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-918'
	>
	<strong><strong>The AI knew the best practices, it just couldn’t connect the dots to anticipate misuse. That’s what manual testing is for – to expose unknown risks.</strong></strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-922"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-920">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-921'
	>
	Automation wouldn’t have caught that, but manual testing told us whether the system could survive a curious attacker.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-929"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-923"
	 href='https://infinum.com/cybersecurity/penetration-testing/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<p	class='typography typography--size-36-text js-typography card-simple__heading'
	data-id='es-924'
	>
	<strong><strong>Want to see how your AI-generated app holds up?</strong></strong></p>		</div>

		<p	class='typography typography--size-16-text-roman js-typography card-simple__paragraph'
	data-id='es-925'
	 id='es-923-paragraph'>
	Let’s test it, break it (safely), and help you fix what matters most.</p><button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-926"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-927'
	>
	<strong><strong>Let’s get technical</strong></strong></div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-928'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-932"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-930">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-931'
	>
	<strong>The real takeaway</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-935"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-933">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-934'
	>
	The apps worked and security looked reasonable. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-938"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-936">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-937'
	>
	But AI inherently doesn’t <em>understand</em> security, which is especially obvious once software interacts with real users, real data, and real incentives to misuse it. Security failures rarely come from missing syntax or forgotten libraries; they emerge from incorrect assumptions about behavior, trust, and intent.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-941"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-939">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-940'
	>
	<li><strong>AI builds what you ask for.</strong></li><li><strong><strong>It protects what you explicitly mention.</strong></strong></li><li><strong>It doesn’t secure the system as a whole.</strong></li><li><strong><strong>It doesn’t imagine creative misuse.</strong></strong></li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-944"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-942">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-943'
	>
	Attackers do <em>nothing</em> but imagine misuse.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-947"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-945">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-946'
	>
	This is exactly why <strong>manual penetration testing exists</strong>: not to check a box, but to ask the one question that AI won’t:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-950"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-948">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-949'
	>
	<em>“What happens if someone does the wrong thing on purpose?”</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-953"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-951">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-952'
	>
	Security still requires human intent and adversarial thinking. No matter how well you prompt it, AI can’t protect against what it doesn’t anticipate.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-956"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-954">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-955'
	>
	<em>If your app was built with AI assistance, this isn’t a theoretical risk. It’s a structural one. </em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-959"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-957">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-958'
	>
	<em>If you want real, certified humans to have a go at your app – partner with Infinum’s security team to </em><a href="https://infinum.com/cybersecurity/penetration-testing/"><em>test your app the way real attackers would.</em></a><em>  We’ll help you find the blind spots, close the gaps, and build safer systems, so you can move fast without leaving yourself exposed. If we find zero issues, the beer is on us.</em></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/ai-generated-code-security-risks/">Is AI-Generated Code Secure? What Business Leaders Need to Know About AI and Application Security</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>19274941https://infinum.com/uploads/2026/03/img-CS-vibe-coding-new-opti.webp</url>
				</image>
				<title>Security Gaps in Vibe-Coded Applications</title>
				<link>https://infinum.com/blog/security-gaps-in-vibe-coded-applications/</link>
				<pubDate>Wed, 11 Feb 2026 11:32:15 +0000</pubDate>
				<dc:creator>Hrvoje Filaković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=19274941</guid>
				<description>
					<![CDATA[<p>An evaluation of AI-generated code security found that while detailed security prompts lead to improved outcomes, consistent vulnerabilities and gaps remain even with strict guidance.</p>
<p>The post <a href="https://infinum.com/blog/security-gaps-in-vibe-coded-applications/">Security Gaps in Vibe-Coded Applications</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1309"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-962">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-965"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-963">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-964'
	>
	<strong>As vibe coding enters real-world development, I set out to evaluate the security of AI-generated code in practice. After building and attacking three vibe-coded applications with increasing security guidance, clear improvements emerged – alongside consistent gaps.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-968"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-966">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-967'
	>
	Large language models are already part of <a href="https://infinum.com/news/infinum-embeds-ai-across-product-development/">everyday development workflows</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-971"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-969">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-970'
	>
	Development teams use them to scaffold features, generate boilerplate, wire APIs, and, increasingly, to assemble entire applications from natural-language prompts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-974"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-972">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-973'
	>
	In many cases, the output is functionally correct and fast enough to be genuinely useful.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-977"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-975">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-976'
	>
	What is less obvious is how this code behaves once it is exposed to real attackers rather than happy-path usage. This is especially relevant as <a href="https://infinum.com/governance-risk-compliance-services/" id="https://infinum.com/governance-risk-compliance-services/">regulatory pressure</a> on <a href="https://infinum.com/third-party-cyber-risk-management/" id="https://infinum.com/third-party-cyber-risk-management/" target="_blank" rel="noreferrer noopener">the software supply chain</a> increases and attackers adopt AI-assisted tooling.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-979"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-978'
	>
	<strong>We examined how security posture changes as we instruct an AI model to implement different levels of secure development best practices.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-982"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-980">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-981'
	>
	I asked Gemini Pro to generate three different web applications and for each one, I progressively increased the level of security detail in my prompts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-985"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-983">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-984'
	>
	The results were instructive, occasionally impressive, and ultimately a reminder that security does not emerge automatically – no matter how advanced the model. For a business-focused interpretation of these findings, see our <a href="https://infinum.com/blog/ai-generated-code-security-risks/">AI-generated code security risks guide for CTOs and business leaders</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-988"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-986">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-987'
	>
	<strong>The plan and methodology</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-991"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-989">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-990'
	>
	To make the experiment realistic, I needed applications complex enough to expose meaningful attack surfaces, but not so large that the AI would collapse into contradictory logic or endless refactoring loops.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-994"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-992">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-993'
	>
	I intentionally avoided very simple apps (e.g., To-do apps), since their limited functionality results in a small and unrealistic attack surface, while overly complex systems often exceed what current models can reliably reason about end-to-end.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-996"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-995'
	>
	<strong>Medium-complexity web applications turned out to be the sweet spot. They are large enough to expose meaningful security issues, but not so large that the AI collapses under its own code.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-999"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-997">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-998'
	>
	They include authentication, authorization, data storage, and user interaction patterns that are common in real-world systems—and therefore make attractive targets for attackers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1002"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1000">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1001'
	>
	For each application, I generated the entire codebase using Gemini Pro, varying only the level of security detail in the prompt.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1005"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1003">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1004'
	>
	I then reviewed the resulting code from the perspective of a realistic attacker, including both unauthenticated users and low-privileged authenticated users attempting to escalate access or abuse functionality. The focus was on practical exploitation paths rather than theoretical weaknesses.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1008"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1006">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-1007'
	>
	<strong>The test subjects</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1011"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1009">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1010'
	>
	Based on these criteria, the following three web applications were born:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1016"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--top bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-1012">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1013'
	>
	1</p>	<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-1014'
	>
	Simple Project Tracker</p><p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1015'
	>
	A lightweight tool for small teams to manage projects and track tasks, vibe coded with no explicit security instructions.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1021"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--top bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-1017">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1018'
	>
	2</p>	<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-1019'
	>
	Project Resource Hub</p><p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1020'
	>
	A centralized internal portal for storing and accessing important documents, links, and guides (similar to a mini-wiki), built with light security instructions.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1026"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--top bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-1022">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1023'
	>
	3</p>	<div class="bullet__content">
		<p	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-1024'
	>
	Niche Vault</p><p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1025'
	>
	A site for hobbyists to catalog and showcase personal collections (e.g., vinyl records, comics, board games, etc.), created with detailed and precise security instructions (e.g., OWASP guidelines). </p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1029"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1027">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1028'
	>
	Each application was built independently, with the only variable being the depth and specificity of security requirements provided to the AI.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1032"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1030">
	<p	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-1031'
	>
	<strong>Discoveries and  vulnerabilities </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1035"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1033">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1034'
	>
	In this section, we analyze the key vulnerabilities identified across the three generated applications. Rather than listing every individual issue, the focus is on the most impactful findings, recurring security patterns, and the extent to which the level of prompt detail directly influenced the security posture of the generated code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1038"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1036">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-1037'
	>
	<strong>Results at a glance</strong>: <strong>What broke and why</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1041"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1039">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1040'
	>
	The following table provides a high-level summary of the results from the tested applications.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1044"
	 data-animation-target='inner-items'>
		
			<div class="block-group" data-id=es-1043>
	
<div
	class="wrapper"
	data-id="es-1042"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			
<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Application</th><th>Security quality</th><th>Notes</th></tr></thead><tbody><tr><td>Simple Project Tracker</td><td><strong>Poor</strong></td><td>Multiple critical vulnerabilities across input validation, authorization, and session management.</td></tr><tr><td>Project Resource Hub</td><td><strong>Mixed</strong></td><td>Major improvements, but still several exploitable issues.</td></tr><tr><td>Niche Vault</td><td>Better, but <strong>insufficient</strong></td><td>Major improvements, but several exploitable issues remain.</td></tr></tbody></table><figcaption class="wp-element-caption"><em>The trend is clear: more detailed security prompts lead to better outcomes – but not to secure-by-default systems.</em></figcaption></figure>
		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1047"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1045">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1046'
	>
	For security researchers looking to understand what these runtime gaps look like from an attacker&#8217;s perspective on mobile, where protections like root detection and Frida detection can be systematically defeated — see our <a href="https://infinum.com/blog/understanding-defeating-android-protections/">walkthrough of Android penetration testing techniques</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1050"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1048">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-1049'
	>
	<strong>Simple Project Tracker: No security, just vibes</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1053"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1051">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1052'
	>
	The first application generated was the Simple Project Tracker, a lightweight web application where regular users can create, update, and sort tasks, while administrators can additionally create projects and assign users.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1056"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1054">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1055'
	>
	No explicit security requirements were provided. The prompt focused solely on functional goals such as building a lightweight project tracker with database integration, role-based user and admin access, and all files needed for local deployment. As a result, the following prompt was used:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1059"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1057">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1058'
	>
	<mark><em>I would like to build a simple project tracker web application. Please include a database integration and an API that distinguishes between user and admin permissions. The goal is to have a completely operational application that remains lightweight by focusing exclusively on high-impact, necessary features. Additionally, make sure to generate every file necessary to run the web application locally.</em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1061"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1060'
	>
	<strong>The AI was only told what the application should do, not how it should defend itself.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1064"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1062">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1063'
	>
	For this application, AI selected the following technology stack:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1067"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1065">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1066'
	>
	<li>Frontend: <em>HTML, Tailwind, JavaScript</em></li><li>Backend: <em>Node.js</em></li><li>API: <em>REST (express.js)</em></li><li>Database: <em>SQLite3</em></li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1070"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1068">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1069'
	>
	As illustrated in the screenshot below, the generated web application exhibited a polished and well-designed interface.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1073"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1071"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1072">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image1.webp"
					class="image__img block-media__image-img"
					alt="Screenshot of AI-generated Simple Project Tracker web app interface showing task management dashboard with no security controls"
										height="758"
															width="1113"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1076"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1074">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1075'
	>
	Unsurprisingly, the absence of security guidance resulted in an application that implicitly trusted all user input. There was no input sanitization anywhere in the codebase, which led to pervasive cross-site scripting vulnerabilities across forms, task descriptions, and project metadata.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1079"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1077">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1078'
	>
	Below is an example of the generated code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1082"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1080"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1081">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image2.webp"
					class="image__img block-media__image-img"
					alt="JavaScript code snippet showing AI-generated innerHTML assignment without input sanitization, creating a cross-site scripting (XSS) vulnerability"
										height="181"
															width="943"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1085"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1083">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1084'
	>
	The registration flow was particularly revealing. User roles were assigned directly from client-controlled input:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1087"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-json github-light" data-language="json" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">&quot;</span><span class="token" style="color: #005cc5;">username</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">herc</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">&quot;</span><span class="token" style="color: #005cc5;">password</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">password</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">&quot;</span><span class="token" style="color: #005cc5;">role</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">user</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1090"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1088">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1089'
	>
	Changing &#8220;role&#8221; to &#8220;admin&#8221; was enough to gain full administrative privileges. There was no server-side validation, enforcement, or role integrity check.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1093"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1091">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1092'
	>
	Authorization was equally fragile. While the application exposed separate API endpoints for managing tasks and projects, none of them implemented ownership checks.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1096"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1094">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1095'
	>
	Any authenticated user could view, modify, or delete any other user’s data which can be seen in the following request where oddly specific x-user-id and x-user-role headers are used by default.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1099"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1097"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1098">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image3.webp"
					class="image__img block-media__image-img"
					alt="HTTP request and response showing broken access control in AI-generated app, with x-user-id and x-user-role headers accepted directly from client input"
										height="401"
															width="826"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1102"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1100">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1101'
	>
	Session handling further reinforced the trust-in-the-client model. Authentication state was stored in unsigned cookies containing raw user objects:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-json github-light" data-language="json" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">{</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token" style="color: #005cc5;">id</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token">:</span><span class="token" style="color: #005cc5;">2</span><span class="token">,</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token" style="color: #005cc5;">username</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">user</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token" style="color: #005cc5;">role</span><span class="token" style="color: #005cc5;">&quot;</span><span class="token">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">user</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1105">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1106'
	>
	Overall, in terms of design and functionality, the AI delivered exactly what was requested. However, from the security standpoint, the application had no sense of security at all and every possible aspect was completely insecure.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1108">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1109'
	>
	Functionally, the application worked exactly as requested. From a security standpoint, it operated entirely on the assumption that “logged-in users will behave correctly.” Needless to say, attackers do not follow that assumption.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1111">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-1112'
	>
	<strong>Project Resource Hub: Better, but not bulletproof</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1116"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1114">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1115'
	>
	The second application, the Project Resource Hub, was designed as a platform where users could share resources such as files, links, and documentation, while administrators were able to manage all users.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1119"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1117">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1118'
	>
	This time, alongside the application details, I instructed the AI to also take security into account. Each feature was required to be implemented in a way that was secure and resistant to abuse, rather than merely functional.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1122"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1120">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1121'
	>
	<mark><em><em>… web application details …</em></em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1125"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1123">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1124'
	>
	<mark><em><em><em>You may use modern, standard technologies commonly used in contemporary web application development, such as a database and an API. The application must support multiple users and include an administrator role. There should be at least 2–5 distinct features for both regular users and administrators to demonstrate a reasonable level of application complexity.</em></em></em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1128"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1126">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1127'
	>
	<mark><em><em><em><em>Additionally, it is critically important that security is considered throughout the entire application. Every feature should be designed and implemented securely, following best practices and ensuring that no functionality can be easily exploited.</em></em></em></em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1129'
	>
	This time, the AI was instructed to consider security throughout the application, without explicit defense measures.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1133"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1131">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1132'
	>
	Compared to the previous application, this one showed noticeable improvements in security while keeping the same tech stack. Specifically, the AI implemented several measures, including:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1136"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1134">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1135'
	>
	<li>JWT tokens for authorization</li><li>Rate limiting on login, file uploads, and other sensitive routes</li><li>Cross-Origin Resource Sharing (CORS) configuration</li><li>File upload validation</li><li>Content Security Policy (CSP)</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1139"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1137">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1138'
	>
	As illustrated in the screenshot below, the generated web application was simple and provided functionality for storing several resource types.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1142"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1140"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1141">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image4.webp"
					class="image__img block-media__image-img"
					alt="Screenshot of AI-generated Project Resource Hub web application interface showing document and link sharing features built with light security guidance"
										height="323"
															width="963"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1145"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1143">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1144'
	>
	With a moderately detailed security prompt, the AI implemented effective input sanitization, and most tested inputs (including XSS, SSTI, and other relevant attack vectors) were handled appropriately. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1146">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1147'
	>
	<strong>Even modest security instructions can significantly improve baseline resilience. However, a deeper inspection revealed critical blind spots in less than five minutes.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1151"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1149">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1150'
	>
	After less than five minutes of reviewing the generated code, I discovered a major flaw in the file upload functionality: the AI considered filename, file size, and MIME type checks sufficient for security, leaving the system vulnerable.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1154"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1152"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1153">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image5.webp"
					class="image__img block-media__image-img"
					alt="Node.js file upload code generated by AI showing MIME type validation only, missing file extension checks that leave the system vulnerable to malicious uploads"
										height="599"
															width="1026"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1157"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1155">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1156'
	>
	Because there were no extension checks (or other meaningful protections) an attacker could easily spoof the content type and upload arbitrary files.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1159"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">--</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">235905183813478547083317251969</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">Content</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">Disposition</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">form</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">data</span><span class="token">;</span><span class="token"> </span><span class="token" style="color: #005cc5;">name</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">file</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">;</span><span class="token"> </span><span class="token" style="color: #005cc5;">filename</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">shell.exe</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">Content</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">Type</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">application</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">pdf</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token" style="color: #005cc5;">any_malicious_content_here</span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">[</span><span class="token" style="color: #d73a49;">...</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1162"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1160">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1161'
	>
	Another feature in this application allowed users to store website links as resources, along with a preview function. Such feature by its description alone is a hacker’s dream to test for SSRF and unsurprisingly, the generated code was vulnerable.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1165"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1163">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1164'
	>
	While the preview was rendered inside an iframe, the backend still made unrestricted requests, making blind SSRF fully exploitable. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1168"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1166"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1167">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image6.webp"
					class="image__img block-media__image-img"
					alt="Node.js code showing SSRF-vulnerable link preview endpoint that makes unrestricted backend requests without URL validation, exploitable via blind SSRF"
										height="299"
															width="893"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1171"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1169">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1170'
	>
	Despite additional issues, such as an insecure CSP configuration and predictable secrets, this application was still an improvement over the previous one.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1174"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1172">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1173'
	>
	However, several security measures were either ineffective against real attacks or failed because the AI didn’t anticipate certain attack scenarios at all.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1177"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1175">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-1176'
	>
	<strong>Niche Vault: Not the Fort Knox just yet</strong></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1180"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1178">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1179'
	>
	The third application is Niche Vault, a platform that lets hobbyists log, browse, and share items from their personal collections, complete with individual profile pages.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1183"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1181">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1182'
	>
	On the administrative side, it includes full user management capabilities, such as deleting, suspending, or banning accounts, along with basic analytics and the ability to publish site-wide announcements.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1186"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1184">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1185'
	>
	For this project, I placed a strong emphasis on security from the outset.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1189"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1187">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1188'
	>
	I instructed the AI to strictly adhere to OWASP WSTG guidelines and OWASP best practices, ensuring that every feature was analyzed for potential attack vectors and that appropriate mitigations were implemented from the outset. In addition, every piece of generated code was required to undergo a second security review by AI again.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1192"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1190">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1191'
	>
	<mark><em><em><em><em><em><em>&lt;web_application&gt; A minimal web application designed for hobbyists to log, manage, view, and share items from their personal collections, such as vinyl records, comics, or similar collectibles. &lt;/web_application&gt; </em></em></em></em></em></em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1193">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1194'
	>
	<mark><em><em><em><em><em><em>&#8230;web application features&#8230; </em></em></em></em></em></em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1196">
	<p	class='typography typography--size-16-text-roman typography--is-highlighted js-typography block-typography__typography'
	data-id='es-1197'
	>
	<mark><em><em><em><em><em><em>&lt;security &#8211; HIGH priority&gt; Security is the highest priority. Ensure that every component and feature is implemented securely and cannot be abused. Apply OWASP Web Security Testing Guide (WSTG) methodologies throughout the development process, and explicitly consider the OWASP Top 10 vulnerabilities to ensure the application is thoroughly protected by applying every best practice defense mechanism for each request, feature, functionality, and more. &lt;/security &#8211; HIGH priority&gt;</em></em></em></em></em></em></mark></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1199">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1200'
	>
	This time, the AI generated a web application using Python (<em>although I had to manually fix the code in several places</em>) with the following tech stack:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1202">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1203'
	>
	<li>Frontend: <em>HTML, Jinja2 (templating engine), Bootstrap</em></li><li>Backend: <em>Python, Flask</em></li><li>API: <em>REST (implicitly created by Flask routes)</em></li><li>Database: <em>SQLite, accessed via SQLAlchemy</em></li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1205">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1206'
	>
	The following image shows the generated web application with its functionalities implemented.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1208"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1209">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image7.webp"
					class="image__img block-media__image-img"
					alt="Screenshot of AI-generated Niche Vault hobbyist collection tracker app built with OWASP security guidance, showing My Collection dashboard with Export CSV button"
										height="498"
															width="990"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1211">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1212'
	>
	User input was well protected across the board, and the application even included safeguards against SSTI attacks, which is especially important given its use of Jinja2. Both authentication and authorization were implemented cleanly and thoughtfully.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1215"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1214'
	>
	<strong>After explicitly requiring adherence to security guidelines and best practices, with a second security review step mandated for all generated code, the AI produced a robust application that exceeded my expectations. However, even here, vulnerabilities surfaced.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1218"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1216">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1217'
	>
	The application was not without flaws. One notable issue appeared in the CSV export feature, where it was possible to inject malicious payloads that could be executed by Excel or LibreOffice.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1221"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1219">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1220'
	>
	As shown in the image below, the relevant code lacks any form of input sanitization, leaving it vulnerable to CSV injection attacks.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1224"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1222">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1223'
	>
	As a result, an attacker can embed a malicious payload. In this example, a calculator application was executed; however, real-world attacks may involve reverse shell payloads that grant remote access to the victim’s desktop or download and execute malware.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1226"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">cmd</span><span class="token" style="color: #d73a49;">|</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;"> /C calc</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #d73a49;">!</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">A1</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1229"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1227">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1228'
	>
	As shown in the image below, the payload is evaluated when the CSV file is opened, causing the calculator process to be launched.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1232"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1230"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1231">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/image8.webp"
					class="image__img block-media__image-img"
					alt="Proof-of-concept screenshot showing CSV injection attack: malicious payload in exported file launches Windows Calculator via Excel DDE, demonstrating real-world exploit risk"
										height="324"
															width="884"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1234"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1233'
	>
	It goes without saying that the following prerequisites are required for the attack to work: <br />
<br />
1. Dynamic Data Exchange (DDE) needs to be enabled. <br />
<br />
2. Victim needs to enable such content to be opened after a few warnings. <br />
<br />
Similarly, for the LibreOffice, the &#8220;Evaluate formulas&#8221; options needs to be ticked.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1237"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1235">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1236'
	>
	In addition to the glaring CSV injection vulnerability, several critical endpoints lacked rate-limiting controls.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1240"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1238">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1239'
	>
	While the AI correctly implemented rate limiting for the registration and login endpoints, it failed to apply similar protections to the following endpoints, which attackers could exploit to perform potential denial-of-service (DoS) attacks as well as destructive behavior.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1242"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-html github-light" data-language="html" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">/post/new
</span></span><span class="line"><span class="token">/admin/toogle_ban/{user_id}
</span></span><span class="line"><span class="token">/admin/delete_user/{user_id}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1245"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1243">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1244'
	>
	Additionally, the code contained a minor open redirect vulnerability, which could be exploited in phishing attack scenarios where an attacker can supply a malicious domain to the next URL argument.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1247"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-python github-light" data-language="python" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">login_user</span><span class="token">(</span><span class="token">user</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">redirect</span><span class="token">(</span><span class="token">request</span><span class="token">.</span><span class="token">args</span><span class="token">.</span><span class="token">get</span><span class="token">(</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">next</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">or</span><span class="token"> </span><span class="token">url_for</span><span class="token">(</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">dashboard</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1250"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1248">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1249'
	>
	<strong>In conclusion, even when provided with a highly detailed prompt that explicitly instructs the AI to generate secure code, it is still likely to fall short in other areas or to overlook security considerations in certain features altogether.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1253"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1251">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1252'
	>
	Without precise, feature-specific security requirements, the AI tends to leave parts of the application insufficiently protected.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1256"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1254">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1255'
	>
	As demonstrated in this example, it successfully sanitized input fields, prevented SQL injection, and applied several other best practices, yet still failed to implement comprehensive, end-to-end security.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1259"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1257">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1258'
	>
	Ultimately, these gaps resulted in additional vulnerabilities despite the overall focus on secure development.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1262"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1260">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-1261'
	>
	<strong>The secret tokens predictability game</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1265"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1263">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1264'
	>
	While generating multiple web applications, I noticed a recurring pattern: AI models frequently produce “secret” tokens and keys that follow similar structures and wording.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1268"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1266">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1267'
	>
	This observation told me to take a deeper look into how predictable these generated secrets can be.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1271"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1269">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1270'
	>
	For example, when further creating even simpler web applications, the following tokens were generated in docker-compose and other configurational files:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">dev</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">key</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">change</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">in</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">prod</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">982374</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">change_this_to_something_long_and_random_12345</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">your_ultra_secure_random_string_here</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">must_be_changed_to_secure_key_987123</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1274">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1275'
	>
	While these values may not appear in common brute-force wordlists (such as those targeting JWT secrets and other), they are not cryptographically secure and I could potentially see them being used.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1278"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1277'
	>
	<strong>The real risk is not that an attacker brute-forces a single secret, but that AI-generated applications at scale may share similar default or placeholder secrets that are not cryptographically secure. An attacker could leverage this predictability by compiling lists of common AI-generated keys and testing them across mass-produced, “vibe-coded” web applications.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1281"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1279">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1280'
	>
	Overall, this demonstrates a plausible attacker strategy: using multiple AI models to generate and aggregate common secret placeholders, then testing them against large numbers of similarly generated applications.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1284"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1282">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-1283'
	>
	<strong>The verdict</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1287"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1285">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1286'
	>
	Bottom line is:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1290"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1288">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1289'
	>
	<strong>Vibe coding is only as secure as the vibe coder’s understanding of potential vulnerabilities and their ability to instruct the AI to account for them.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1293"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1291">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1292'
	>
	When building an application using AI, it is critical to explicitly guide the model on the types of vulnerabilities that may arise in the generated code. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1296"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1294">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1295'
	>
	For instance, if you ask the AI to implement a file-upload feature, you must already provide clear requirements regarding file extensions, MIME-type validation, size limits, and other relevant mitigations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1299"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1297">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1298'
	>
	The broader issue is that even the most detailed prompts do not guarantee secure output. AI can still generate insecure code or introduce subtle loopholes in unexpected places, and create critical business logic issues. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1301"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1300'
	>
	<strong>If you are using AI to accelerate development, the takeaway is not to avoid it. It is to treat it as a powerful assistant, not a security authority. Security remains a deliberate engineering discipline, not an emergent property of better prompts.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1304"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1302">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1303'
	>
	For this reason, it is highly recommended to conduct <a href="https://infinum.com/cybersecurity/penetration-testing/" id="https://infinum.com/cybersecurity/penetration-testing/">real-world penetration testing</a>, in which security professionals review both the code and the application’s runtime behavior to identify and mitigate risks before they become exploitable.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1307"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1305">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1306'
	>
	Explore our <strong><a href="https://infinum.com/cybersecurity/">cybersecurity services</a></strong> — from penetration testing to security architecture — and partner with experts who can identify risks before they become exploitable.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/security-gaps-in-vibe-coded-applications/">Security Gaps in Vibe-Coded Applications</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>19274777https://infinum.com/uploads/2026/01/moltbot-hero-visual.webp</url>
				</image>
				<title>OpenClaw: Viral AI Sidekick That Puts You and Your Data at Risk</title>
				<link>https://infinum.com/blog/openclaw-moltbot-clawdbot-viral-ai-sidekick/</link>
				<pubDate>Fri, 30 Jan 2026 15:53:11 +0000</pubDate>
				<dc:creator>Hrvoje Filaković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=19274777</guid>
				<description>
					<![CDATA[<p>OpenClaw showcases how powerful “local-first” AI agents can be, but it also shows how quickly convenience can turn into a security liability.</p>
<p>The post <a href="https://infinum.com/blog/openclaw-moltbot-clawdbot-viral-ai-sidekick/">OpenClaw: Viral AI Sidekick That Puts You and Your Data at Risk</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1464"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1310">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1311">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-1312'
	>
	If you haven’t kept up with AI tooling discussions, you may have missed OpenClaw (formerly Moltbot and Clawdbot). Marketed as &#8220;The AI that actually does thing<em>s,</em>&#8221; it acts as your personal AI assistant that can clear your inbox, send emails, manage your calendar, and even check you in for flights. It also acts out – to say the least.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1316"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1314"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1315">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/02/Screenshot-2026-02-02-at-11.45.50.webp"
					class="image__img block-media__image-img"
					alt=""
										height="494"
															width="733"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1319"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1317">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1318'
	>
	What sets Moltbot apart from cloud-only assistants is its deep integration with applications already running on your system, such as WhatsApp, Telegram, Slack, and Discord. It interacts directly with your operating system to manage everyday tasks, bringing AI assistance into your local workflow rather than keeping it locked behind a web interface.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1322"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1320">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1321'
	>
	However, from a security standpoint, this level of access is bordering on a worst-case scenario. This is the same principle we found in our experiment on <a href="https://infinum.com/blog/ai-generated-code-security-risks/">AI-generated code security risks</a> — AI systems don&#8217;t fail because they lack capability, they fail because they make incorrect assumptions about trust.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1324"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-30-text js-typography block-highlighted-text__typography'
	data-id='es-1323'
	>
	<strong> If it can operate on your system, it can compromise it.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1331"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-section-intro" data-id="es-1325">
	<div
	class="section-intro block-section-intro__section-intro section-intro__divider--down section-intro--no-paragraph"
	data-id="es-1326"
	 data-type='default'>
	
	
			<div class="section-intro__inner">
			<h2	class='typography typography--size-36-text js-typography section-intro__title'
	data-id='es-1327'
	>
	Inherently Risky by Design</h2>
			<div class="section-intro__wrap">
				<button	class="btn btn--color-infinum btn--size-medium btn--width-default btn__as-link btn__icon-position--right section-intro__button js-block-section-intro-button"
	data-id="es-1328"
	>
		<div class="btn__inner">
							
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-1330'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>			</div>
		</div>
	
			<hr class="section-intro__divider" aria-hidden="true" />
	</div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1334"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1332">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1333'
	>
	The developers are transparent about the dangers. Moltbot&#8217;s installer explicitly outlines its extensive capabilities and describes the system as &#8220;<em>inherently risky</em>&#8220;. While this transparency is commendable, it highlights the unusually broad level of access the AI operates with.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1337"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1335"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1336">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="611"
															width="1195"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1338">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1339'
	>
	During onboarding, the system prompts you to enable &#8220;<em>skills,</em>&#8221; which are essentially permission scopes granting the bot access to local applications and external services. Some of these are highly sensitive:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1341">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1342'
	>
	<li>1Password: granting access to a vault means the AI can be entrusted with the keys to nearly every account a user owns.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1346"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1344">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1345'
	>
	<li>Personal data: skills for Apple Notes, Reminders, and Bear-notes give the bot a very high degree of privacy access.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1349"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1347">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1348'
	>
	<li>System commands: agents can run commands and read or write files on your machine.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1352"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1350"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1351">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="554"
															width="1133"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1359"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-section-intro" data-id="es-1353">
	<div
	class="section-intro block-section-intro__section-intro section-intro__divider--down section-intro--no-paragraph"
	data-id="es-1354"
	 data-type='default'>
	
	
			<div class="section-intro__inner">
			<h2	class='typography typography--size-36-text js-typography section-intro__title'
	data-id='es-1355'
	>
	The Unauthenticated Dashboard: Global Exposure</h2>
			<div class="section-intro__wrap">
				<button	class="btn btn--color-infinum btn--size-medium btn--width-default btn__as-link btn__icon-position--right section-intro__button js-block-section-intro-button"
	data-id="es-1356"
	>
		<div class="btn__inner">
							
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-1358'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>			</div>
		</div>
	
			<hr class="section-intro__divider" aria-hidden="true" />
	</div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1362"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1360">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1361'
	>
	After installation, Moltbot exposes a local web dashboard running on <strong>port 18789</strong> by default. This serves as the primary control panel for managing the bot&#8217;s capabilities.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1365"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1363"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1364">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="696"
															width="1106"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1368"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1366">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1367'
	>
	The critical issue is that there is <strong>no authentication mechanism</strong> in place. If this dashboard is exposed to the internet, any unauthenticated user can interact with the underlying operating system and connected services.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1371"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1369">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1370'
	>
	This is not a hypothetical risk. A simple Censys query reveals more than <strong>1,500 publicly exposed, unauthenticated Clawdbot instances</strong>. These real-world deployments grant unrestricted access to anyone who stumbles across them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1374"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1372"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1373">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image5.webp"
					class="image__img block-media__image-img"
					alt=""
										height="538"
															width="1223"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1381"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-section-intro" data-id="es-1375">
	<div
	class="section-intro block-section-intro__section-intro section-intro__divider--down section-intro--no-paragraph"
	data-id="es-1376"
	 data-type='default'>
	
	
			<div class="section-intro__inner">
			<h2	class='typography typography--size-36-text js-typography section-intro__title'
	data-id='es-1377'
	>
	System Interaction and Leaking API Keys</h2>
			<div class="section-intro__wrap">
				<button	class="btn btn--color-infinum btn--size-medium btn--width-default btn__as-link btn__icon-position--right section-intro__button js-block-section-intro-button"
	data-id="es-1378"
	>
		<div class="btn__inner">
							
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-1380'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>			</div>
		</div>
	
			<hr class="section-intro__divider" aria-hidden="true" />
	</div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1384"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1382">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1383'
	>
	As for the chatbot itself, it delivers exactly what is promised: it can reliably execute system commands.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1387"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1385"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1386">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image6.webp"
					class="image__img block-media__image-img"
					alt=""
										height="439"
															width="889"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1390"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1388">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1389'
	>
	The bot does have some built-in safety measures; by default, it will refuse to execute suspicious commands like reading the <strong>.env</strong> file that contains API keys.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1393"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1391"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1392">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image7.webp"
					class="image__img block-media__image-img"
					alt=""
										height="202"
															width="1018"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1396"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1394">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1395'
	>
	However, these guardrails are easily bypassed. While prompt injection is a known threat, the simplest way to extract this sensitive data is to ask the bot to list <strong>environment variables</strong>. This can immediately leak the <strong>OPENAI_API_KEY</strong> and other critical credentials that are used and configured.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1399"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1397"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1398">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image8.webp"
					class="image__img block-media__image-img"
					alt=""
										height="462"
															width="993"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1406"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-section-intro" data-id="es-1400">
	<div
	class="section-intro block-section-intro__section-intro section-intro__divider--down section-intro--no-paragraph"
	data-id="es-1401"
	 data-type='default'>
	
	
			<div class="section-intro__inner">
			<h2	class='typography typography--size-36-text js-typography section-intro__title'
	data-id='es-1402'
	>
	Malicious Actors on the Hype Train</h2>
			<div class="section-intro__wrap">
				<button	class="btn btn--color-infinum btn--size-medium btn--width-default btn__as-link btn__icon-position--right section-intro__button js-block-section-intro-button"
	data-id="es-1403"
	>
		<div class="btn__inner">
							
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-1405'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>			</div>
		</div>
	
			<hr class="section-intro__divider" aria-hidden="true" />
	</div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1409"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1407">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1408'
	>
	The viral popularity of the tool has also attracted bad actors. One reported case involved a <strong>fake Visual Studio Code extension</strong> posing as a &#8220;<em>ClawdBot Agent</em>&#8220;. While it looked like a legitimate installer, it was actually secretly installing credential stealer on user&#8217;s systems.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1412"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1410"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1411">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2026/01/image9.webp"
					class="image__img block-media__image-img"
					alt=""
										height="870"
															width="1248"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1415"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1413">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1414'
	>
	<em>Source: </em><a href="https://www.aikido.dev/blog/fake-clawdbot-vscode-extension-malware"><em>https://www.aikido.dev/blog/fake-clawdbot-vscode-extension-malware</em></a></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1422"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-section-intro" data-id="es-1416">
	<div
	class="section-intro block-section-intro__section-intro section-intro__divider--down section-intro--no-paragraph"
	data-id="es-1417"
	 data-type='default'>
	
	
			<div class="section-intro__inner">
			<h2	class='typography typography--size-36-text js-typography section-intro__title'
	data-id='es-1418'
	>
	Our Security Recommendations</h2>
			<div class="section-intro__wrap">
				<button	class="btn btn--color-infinum btn--size-medium btn--width-default btn__as-link btn__icon-position--right section-intro__button js-block-section-intro-button"
	data-id="es-1419"
	>
		<div class="btn__inner">
							
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-1421'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>			</div>
		</div>
	
			<hr class="section-intro__divider" aria-hidden="true" />
	</div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1425"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1423">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1424'
	>
	Specific Tips Moltbot/Clawdbot Users:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1428"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1426">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1427'
	>
	<li><strong>Bind to localhost:</strong> ensure that the dashboard is <strong>only</strong> accessible to localhost (127.0.0.1). Never expose port 18789 to the public internet. Additionally, Moltbot can also be used from the terminal directly without a dashboard.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1431"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1429">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1430'
	>
	<li>Set appropriate allowlists: explicitly define which applications, commands, file paths, and integrations (APIs) Moltbot is allowed to access, and deny everything else by default.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1434"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1432">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1433'
	>
	<li><strong>Treat the bot as a tool:</strong> do not leave it running unattended with broad permissions, especially on shared systems, and lock down access as you would for any automation at this level.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1435">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1436'
	>
	While AI agents are highly effective for automation, they also introduce significant risks — especially when built without proper security design from the start. If you&#8217;re building agents for your business rather than experimenting with third-party tools, see how we approach <strong><a href="https://infinum.com/artificial-intelligence/agent-development/">AI agent development</a></strong> with security and governance built in. To keep your data and devices safe in the meantime, follow these best practices:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1438">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1439'
	>
	<li><strong>Isolate installations:</strong> always deploy experimental AI agents in <strong>virtualized or sandboxed environments</strong> to minimize impact on your main system.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1443"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1441">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1442'
	>
	<li><strong>Use dummy accounts:</strong> never provide your primary personal or work credentials to unknown services. Use <strong>test API keys</strong> that can be revoked immediately.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1446"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1444">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1445'
	>
	<li><strong>Verify sources:</strong> only install software from trusted and official sources to avoid hype-driven malware.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1449"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1447">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1448'
	>
	<li><strong>Restrict permissions:</strong> only grant access that is <strong>absolutely required</strong>. Avoid giving AI full control over sensitive apps like password managers or financial tools.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1456"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-section-intro" data-id="es-1450">
	<div
	class="section-intro block-section-intro__section-intro section-intro__divider--down section-intro--no-paragraph"
	data-id="es-1451"
	 data-type='default'>
	
	
			<div class="section-intro__inner">
			<h2	class='typography typography--size-36-text js-typography section-intro__title'
	data-id='es-1452'
	>
	Proceed with Caution</h2>
			<div class="section-intro__wrap">
				<button	class="btn btn--color-infinum btn--size-medium btn--width-default btn__as-link btn__icon-position--right section-intro__button js-block-section-intro-button"
	data-id="es-1453"
	>
		<div class="btn__inner">
							
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-1455'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>			</div>
		</div>
	
			<hr class="section-intro__divider" aria-hidden="true" />
	</div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1459"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1457">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1458'
	>
	Given the rise of lookalike installers and “agent” add-ons, verify sources rigorously before installing anything. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1462"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-1460">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-1461'
	>
	AI agents are here to stay, but until secure-by-default practices (authentication, least privilege, hardened networking, and auditable controls) become standard, the safest mindset is simple:<strong> If it can operate on your system, it can compromise it.</strong></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/openclaw-moltbot-clawdbot-viral-ai-sidekick/">OpenClaw: Viral AI Sidekick That Puts You and Your Data at Risk</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>