<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeff Tham</title>
    <description>The latest articles on DEV Community by Jeff Tham (@jeff_shieldly).</description>
    <link>https://dev.to/jeff_shieldly</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3994190%2Ff6fd9730-40fa-48e6-9c93-9f22c51bc149.png</url>
      <title>DEV Community: Jeff Tham</title>
      <link>https://dev.to/jeff_shieldly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeff_shieldly"/>
    <language>en</language>
    <item>
      <title>Shieldly Launch Offer: AI-Powered AWS IAM Security from $1.90/Month</title>
      <dc:creator>Jeff Tham</dc:creator>
      <pubDate>Sat, 20 Jun 2026 18:44:42 +0000</pubDate>
      <link>https://dev.to/jeff_shieldly/shieldly-launch-offer-ai-powered-aws-iam-security-from-190month-29ml</link>
      <guid>https://dev.to/jeff_shieldly/shieldly-launch-offer-ai-powered-aws-iam-security-from-190month-29ml</guid>
      <description>&lt;p&gt;We launched Shieldly last week — AI-Powered security analysis for AWS IAM policies, CloudFormation templates, and costs.&lt;/p&gt;

&lt;p&gt;The reaction so far has been consistent: "Why does every other IAM tool require an enterprise contract before I can see a single finding?"&lt;/p&gt;

&lt;p&gt;We agree. So here's our answer:&lt;/p&gt;

&lt;h2&gt;
  
  
  Free — no signup, no credit card
&lt;/h2&gt;

&lt;p&gt;Paste an IAM policy into the IAM Advisor and get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Risk score&lt;/li&gt;
&lt;li&gt;Every finding explained in plain English&lt;/li&gt;
&lt;li&gt;Prioritized remediation steps&lt;/li&gt;
&lt;li&gt;Privilege escalation chain detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No account needed. No AWS credentials required. Just paste and go: &lt;strong&gt;&lt;a href="https://www.shieldly.io/app/iam" rel="noopener noreferrer"&gt;shieldly.io/app/iam&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced features — from $1.90/month
&lt;/h2&gt;

&lt;p&gt;For teams that want continuous analysis across CLI, CI, and IDE:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New customer offer: code &lt;code&gt;90Off2M&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
→ 90% off your first 2 months&lt;br&gt;
→ Pro plan: $19/mo → &lt;strong&gt;$1.90/mo&lt;/strong&gt;&lt;br&gt;
→ Team plan: $49/mo → &lt;strong&gt;$4.90/mo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apply the code at checkout: &lt;a href="https://www.shieldly.io/pricing" rel="noopener noreferrer"&gt;shieldly.io/pricing&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get on Pro
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;500 analyses/day (vs 20 free)&lt;/li&gt;
&lt;li&gt;Advanced AI model (deeper reasoning on complex policies)&lt;/li&gt;
&lt;li&gt;CLI: &lt;code&gt;npx @shieldly/cli analyze policy.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Action: catches IAM risks in every PR&lt;/li&gt;
&lt;li&gt;VS Code extension: analysis as you write&lt;/li&gt;
&lt;li&gt;CloudFormation security scanning&lt;/li&gt;
&lt;li&gt;AWS cost analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why we made the free tier genuinely useful
&lt;/h2&gt;

&lt;p&gt;The engineer who wrote the policy is the one who can fix it. If the tool requires a purchase order before they can see a finding, the finding never gets fixed.&lt;/p&gt;

&lt;p&gt;The demo exists to give that engineer the information — right now, for free. The paid plan exists for teams that want the same analysis baked into their CI pipeline.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Try it free at &lt;a href="https://www.shieldly.io/app/iam" rel="noopener noreferrer"&gt;shieldly.io/app/iam&lt;/a&gt; or use code &lt;code&gt;90Off2M&lt;/code&gt; at checkout for 90% off your first 2 months.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>AWS IAM Least Privilege: A Practical Guide to Scoping Down Policies</title>
      <dc:creator>Jeff Tham</dc:creator>
      <pubDate>Sat, 20 Jun 2026 14:16:52 +0000</pubDate>
      <link>https://dev.to/jeff_shieldly/aws-iam-least-privilege-a-practical-guide-to-scoping-down-policies-249a</link>
      <guid>https://dev.to/jeff_shieldly/aws-iam-least-privilege-a-practical-guide-to-scoping-down-policies-249a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.shieldly.io/blog/" rel="noopener noreferrer"&gt;shieldly.io/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Least privilege" — granting an identity only the permissions it needs and nothing more — is the most repeated advice in AWS security and the least often followed. Not because teams disagree with it, but because manually scoping every policy is tedious, and an over-broad policy "just works." Here is a practical workflow for getting there without grinding your team to a halt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start From Zero, Not From Star
&lt;/h2&gt;

&lt;p&gt;The most common mistake is to begin with a broad grant and plan to tighten it "later." Later never comes. Start with an empty policy and add only the specific actions a workload fails without. It is far easier to add a missing permission than to discover which of a hundred granted permissions are actually unused.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope Three Things: Actions, Resources, Conditions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actions.&lt;/strong&gt; Replace service wildcards like &lt;code&gt;s3:*&lt;/code&gt; with the exact operations needed — &lt;code&gt;s3:GetObject&lt;/code&gt;, &lt;code&gt;s3:PutObject&lt;/code&gt;. Avoid &lt;code&gt;iam:*&lt;/code&gt; entirely outside of break-glass admin roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources.&lt;/strong&gt; Replace &lt;code&gt;Resource: "*"&lt;/code&gt; with explicit ARNs. A policy that needs one bucket should name that bucket, not all of S3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditions.&lt;/strong&gt; Add condition keys to constrain &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;from where&lt;/em&gt; a permission applies — &lt;code&gt;aws:SourceIp&lt;/code&gt;, &lt;code&gt;aws:PrincipalOrgID&lt;/code&gt;, &lt;code&gt;aws:SecureTransport&lt;/code&gt;, or &lt;code&gt;s3:prefix&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Before and After
&lt;/h2&gt;

&lt;p&gt;The over-permissive version — broad and easy, but a blank cheque:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The least-privilege version — scoped to the actions, the bucket, and TLS only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-app-uploads/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Bool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"aws:SecureTransport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Be Careful With AWS Managed Policies
&lt;/h2&gt;

&lt;p&gt;AWS managed policies are convenient but deliberately broad — they are designed to fit many use cases, not yours. Attaching &lt;code&gt;AmazonS3FullAccess&lt;/code&gt; to grant read access to one bucket hands over delete and policy-write permissions across every bucket in the account. Prefer customer-managed policies you can scope precisely, and reserve managed policies for cases where their breadth is genuinely required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the Right AWS Signals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Last-accessed data.&lt;/strong&gt; IAM Access Advisor shows which services a role has actually used. Permissions for services that have never been touched are safe candidates to remove.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM Access Analyzer.&lt;/strong&gt; Generates least-privilege policies from CloudTrail activity and flags resources shared outside your account or organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Make It Continuous, Not a One-Off
&lt;/h2&gt;

&lt;p&gt;Least privilege drifts. New features add permissions, copied snippets reintroduce wildcards, and "temporary" grants become permanent. Bake policy review into the places changes happen — pull requests, CI, and IaC synth — so a regression is caught before it ships rather than in an annual audit.&lt;/p&gt;

&lt;p&gt;AI-Powered IAM analysis can score each policy against least-privilege principles, explain &lt;em&gt;why&lt;/em&gt; a grant is too broad, and propose a scoped-down replacement — in the CLI, a GitHub Action, the VS Code extension, or CDK Guard, so least privilege gets enforced on every change instead of forgotten.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Scope down your IAM policies in seconds — paste one into &lt;a href="https://www.shieldly.io/app/iam" rel="noopener noreferrer"&gt;Shieldly's free AI-Powered analysis&lt;/a&gt;. No signup, no credit card.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>AWS IAM Privilege Escalation: Common Paths and How to Catch Them</title>
      <dc:creator>Jeff Tham</dc:creator>
      <pubDate>Sat, 20 Jun 2026 14:12:54 +0000</pubDate>
      <link>https://dev.to/jeff_shieldly/aws-iam-privilege-escalation-common-paths-and-how-to-catch-them-15an</link>
      <guid>https://dev.to/jeff_shieldly/aws-iam-privilege-escalation-common-paths-and-how-to-catch-them-15an</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.shieldly.io/blog/" rel="noopener noreferrer"&gt;shieldly.io/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Privilege escalation is the moment a limited AWS identity gains permissions it was never meant to have. It rarely comes from a single "admin" policy. Far more often it hides in an innocent-looking combination of permissions that, chained together, let a low-privileged user, role, or compromised credential promote itself to full account control.&lt;/p&gt;

&lt;p&gt;Because each individual permission looks reasonable on its own, these paths slip past human review and rule-based scanners alike. Below are the escalation patterns we see most often, why they work, and how to find them in your own policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes Privilege Escalation Possible
&lt;/h2&gt;

&lt;p&gt;Every escalation path exploits the same idea: some IAM actions let you change &lt;em&gt;who can do what&lt;/em&gt;, or let you run code as a more privileged identity. If a principal can modify policies, attach permissions, pass roles, or create compute that assumes a role, it can usually reach administrator access in one or two steps.&lt;/p&gt;

&lt;p&gt;The danger is contextual. &lt;code&gt;iam:PassRole&lt;/code&gt; is harmless until it is paired with a service that runs code. &lt;code&gt;iam:CreatePolicyVersion&lt;/code&gt; is fine until the principal can point it at a policy attached to itself. Risk lives in the &lt;em&gt;combination&lt;/em&gt;, not the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Common Escalation Paths
&lt;/h2&gt;

&lt;p&gt;These are the high-frequency patterns documented in IAM privilege escalation research (including the well-known Rhino Security Labs catalog). If a non-admin identity holds any of them, treat it as effectively admin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PassRole + RunInstances.&lt;/strong&gt; &lt;code&gt;iam:PassRole&lt;/code&gt; plus &lt;code&gt;ec2:RunInstances&lt;/code&gt; lets a principal launch an EC2 instance with an administrator instance profile, then use that instance's credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PassRole + Lambda.&lt;/strong&gt; &lt;code&gt;iam:PassRole&lt;/code&gt; with &lt;code&gt;lambda:CreateFunction&lt;/code&gt; and &lt;code&gt;lambda:InvokeFunction&lt;/code&gt; lets an attacker create a function that runs as a privileged role and execute arbitrary AWS API calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CreatePolicyVersion.&lt;/strong&gt; &lt;code&gt;iam:CreatePolicyVersion&lt;/code&gt; on a managed policy the principal is attached to lets it write a brand-new default version granting &lt;code&gt;"Action": "*"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AttachUserPolicy / AttachRolePolicy.&lt;/strong&gt; The ability to attach &lt;code&gt;AdministratorAccess&lt;/code&gt; to yourself is a one-call path to full control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PutUserPolicy / PutRolePolicy.&lt;/strong&gt; Inline-policy write permission lets a principal grant itself any permission directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UpdateAssumeRolePolicy.&lt;/strong&gt; Rewriting a privileged role's trust policy to trust the attacker, then assuming it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CreateAccessKey.&lt;/strong&gt; Minting access keys for a more privileged user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What an Escalation Policy Looks Like
&lt;/h2&gt;

&lt;p&gt;The policy below grants only two actions. Neither is &lt;code&gt;*&lt;/code&gt;, and a quick glance might wave it through a code review. Together they are a direct path to administrator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"iam:PassRole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ec2:RunInstances"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is to scope &lt;code&gt;iam:PassRole&lt;/code&gt; to the specific, least-privileged roles the workload actually needs, and constrain it with a &lt;code&gt;iam:PassedToService&lt;/code&gt; condition so the role can only be handed to the intended service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Static Tools Miss These
&lt;/h2&gt;

&lt;p&gt;Rule-based linters evaluate permissions in isolation: they flag a wildcard, an &lt;code&gt;iam:*&lt;/code&gt;, or a known-bad action. But an escalation path is an &lt;em&gt;interaction&lt;/em&gt; between permissions that are individually benign. Detecting it requires reasoning about the attack chain — what each permission unlocks when combined with the others in the same policy and the surrounding account.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Find Privilege Escalation in Your Policies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inventory the dangerous actions.&lt;/strong&gt; Search every policy for &lt;code&gt;iam:PassRole&lt;/code&gt;, &lt;code&gt;iam:Create*&lt;/code&gt;, &lt;code&gt;iam:Attach*&lt;/code&gt;, &lt;code&gt;iam:Put*&lt;/code&gt;, and &lt;code&gt;iam:UpdateAssumeRolePolicy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope and condition them.&lt;/strong&gt; Replace &lt;code&gt;Resource: *&lt;/code&gt; with explicit ARNs and add conditions that limit which roles and services are in play.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze the whole policy, not the line.&lt;/strong&gt; AI-Powered IAM analysis reads the full policy in context, detects multi-step escalation chains, and returns a risk score plus concrete remediation for each finding — the kind of reasoning rule engines can't do.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Find privilege escalation before attackers do — paste an IAM policy into &lt;a href="https://www.shieldly.io/app/iam" rel="noopener noreferrer"&gt;Shieldly's free AI-Powered analysis&lt;/a&gt;. No signup, no credit card.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Why Wildcards in AWS IAM Policies Are Dangerous (and How to Fix Them)</title>
      <dc:creator>Jeff Tham</dc:creator>
      <pubDate>Sat, 20 Jun 2026 14:10:36 +0000</pubDate>
      <link>https://dev.to/jeff_shieldly/why-wildcards-in-aws-iam-policies-are-dangerous-and-how-to-fix-them-15e5</link>
      <guid>https://dev.to/jeff_shieldly/why-wildcards-in-aws-iam-policies-are-dangerous-and-how-to-fix-them-15e5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.shieldly.io/blog/" rel="noopener noreferrer"&gt;shieldly.io/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The asterisk is the single most overused character in AWS IAM. It is quick to type, it makes errors disappear, and it is the root cause of a huge share of real cloud breaches. There are three wildcards that matter most — in the &lt;code&gt;Action&lt;/code&gt;, &lt;code&gt;Resource&lt;/code&gt;, and &lt;code&gt;Principal&lt;/code&gt; fields — and each one grants far more than most teams realize.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Action: * — Every Operation, Including Destructive Ones
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;"Action": "*"&lt;/code&gt; grants every API operation across every service. Even the narrower &lt;code&gt;"s3:*"&lt;/code&gt; is dangerous: it bundles read, write, &lt;code&gt;DeleteObject&lt;/code&gt;, &lt;code&gt;DeleteBucket&lt;/code&gt;, and &lt;code&gt;PutBucketPolicy&lt;/code&gt; — meaning a credential intended to upload a file can also wipe the bucket or rewrite its access policy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is administrator access by another name. If you see it outside a dedicated, tightly controlled admin role, treat it as a critical finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Resource: * — Across Every Object in the Account
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;"Resource": "*"&lt;/code&gt; applies the granted actions to every resource the service has. &lt;code&gt;s3:GetObject&lt;/code&gt; on &lt;code&gt;*&lt;/code&gt; can read every object in every bucket — not just the one the workload needs. Scope to explicit ARNs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-app-uploads/*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few IAM and account-level actions genuinely require &lt;code&gt;*&lt;/code&gt; because they have no resource ARN, but they are the exception. For the vast majority of policies, a real ARN belongs there.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Principal: * — Open to the Entire Internet
&lt;/h2&gt;

&lt;p&gt;On resource-based policies (S3 bucket policies, KMS key policies, SQS, SNS, Lambda), &lt;code&gt;"Principal": "*"&lt;/code&gt; means &lt;em&gt;anyone&lt;/em&gt; — including anonymous, unauthenticated callers — unless a condition narrows it. This is how buckets end up publicly readable. If you must use it, always pair it with a strict condition such as &lt;code&gt;aws:PrincipalOrgID&lt;/code&gt; or &lt;code&gt;aws:SourceArn&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"aws:PrincipalOrgID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"o-exampleorgid"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Scope Wildcards Down
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enumerate the actions you actually call.&lt;/strong&gt; Use CloudTrail or IAM Access Analyzer to see which operations the identity uses, then list only those.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name your resources.&lt;/strong&gt; Replace &lt;code&gt;*&lt;/code&gt; with specific ARNs; use path prefixes where you need a group of objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constrain principals with conditions.&lt;/strong&gt; Never leave &lt;code&gt;Principal: *&lt;/code&gt; unconditioned on a resource policy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch them automatically.&lt;/strong&gt; Wildcards reappear constantly as policies change. Run them through an AI-Powered IAM analyzer that flags every risky wildcard, explains the real-world exposure it creates, and proposes a scoped replacement.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Catch IAM risks automatically — paste a policy into &lt;a href="https://www.shieldly.io/app/iam" rel="noopener noreferrer"&gt;Shieldly's free AI-Powered analysis&lt;/a&gt;. No signup, no credit card.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
