Security Checks¶
These checks identify security risks and violations of AWS IAM best practices.
full_wildcard¶
Detects the most dangerous pattern: Action: "*" with Resource: "*".
Severity: critical
Why It's Critical¶
This grants full administrator access to the entire AWS account, equivalent to the AdministratorAccess managed policy.
Fail Example¶
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
How to Fix¶
Replace with specific actions and resources:
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
wildcard_action¶
Detects Action: "*" without specifying which service.
Severity: medium
Fail Example¶
{
"Effect": "Allow",
"Action": "*",
"Resource": "arn:aws:s3:::bucket/*"
}
How to Fix¶
Specify the actions needed:
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": "arn:aws:s3:::bucket/*"
}
wildcard_resource¶
Detects Resource: "*" (access to all resources).
Severity: medium (may be lowered to low with resource-scoping conditions)
When It's Acceptable¶
Some actions require Resource: "*":
s3:ListAllMyBucketsiam:GetAccountSummary- Many
Describe*andList*actions
Condition-Aware Severity¶
This check intelligently adjusts severity based on conditions that restrict resource scope:
Global Resource-Scoping Conditions (Always Lower Severity)¶
These conditions are always valid for all services and directly constrain which resources can be accessed:
| Condition Key | Effect | Severity |
|---|---|---|
aws:ResourceAccount |
Limits to specific AWS account(s) | low |
aws:ResourceOrgID |
Limits to specific AWS Organization | low |
aws:ResourceOrgPaths |
Limits to specific OU paths | low |
Example (severity = low):
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceAccount": "${aws:PrincipalAccount}"
}
}
}
Resource Tag Conditions (Conditional)¶
aws:ResourceTag/* conditions lower severity only if ALL actions in the statement support the condition. Support is validated against AWS service definitions.
Example - SSM with tag support (severity = low):
{
"Effect": "Allow",
"Action": ["ssm:StartSession", "ssm:GetConnectionStatus"],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Component": "bastion"
}
}
}
Example - Mixed actions, partial support (severity = medium):
{
"Effect": "Allow",
"Action": ["s3:GetObject", "route53:ChangeResourceRecordSets"],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Env": "prod"
}
}
}
In this case, s3:GetObject supports aws:ResourceTag but route53:ChangeResourceRecordSets does not, so the severity remains medium.
How to Fix¶
Restrict to specific resources:
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::specific-bucket/*"
}
Or use resource-scoping conditions:
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceAccount": "123456789012"
}
}
}
service_wildcard¶
Detects service-level wildcards like s3:* or iam:* that grant all permissions for a service.
Severity: high (may be lowered to low with ABAC tag conditions)
Fail Example¶
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
How to Fix¶
Use specific actions or action patterns:
{
"Effect": "Allow",
"Action": ["s3:Get*", "s3:List*"],
"Resource": "*"
}
ABAC-Aware Severity¶
When a statement uses a service wildcard but restricts access via ABAC tag conditions —
where aws:ResourceTag/* is compared against ${aws:PrincipalTag/*} — the finding is
still reported but at a reduced severity (low by default). The wildcard remains an
auditable finding, but the tag-based ownership constraint meaningfully limits its blast radius.
Detected pattern:
{
"Effect": "Allow",
"Action": ["secretsmanager:*"],
"Resource": "arn:aws:secretsmanager:*:123456789012:secret:*",
"Condition": {
"StringLike": {
"aws:ResourceTag/owner": "${aws:PrincipalTag/owner}",
"aws:ResourceTag/env": "${aws:PrincipalTag/env}"
}
}
}
This applies to any service, not only secretsmanager.
Configuration Options¶
service_wildcard:
enabled: true
# Severity for wildcards without ABAC mitigation (default: high)
severity: high
# Severity when ABAC ResourceTag/PrincipalTag conditions are present (default: low)
abac_mitigated_severity: low
# Services exempt from this check entirely
allowed_services:
- logs
- cloudwatch
| Option | Type | Default | Description |
|---|---|---|---|
severity |
string | high |
Severity for service wildcards without ABAC conditions |
abac_mitigated_severity |
string | low |
Severity when aws:ResourceTag/* = ${aws:PrincipalTag/*} conditions present |
allowed_services |
list of string | [] |
Service prefixes (e.g. logs, s3) that are exempt from this check |
sensitive_action¶
Detects 490+ privilege escalation actions that should have conditions.
Severity: medium
Sensitive Action Categories¶
- IAM Management:
iam:CreateUser,iam:AttachRolePolicy,iam:PassRole - Security Controls:
iam:DeletePolicy,kms:DisableKey - Data Access:
s3:DeleteBucket,rds:DeleteDBInstance
Fail Example¶
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "*"
}
How to Fix¶
Add conditions to restrict usage:
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/lambda-*",
"Condition": {
"StringEquals": {
"iam:PassedToService": "lambda.amazonaws.com"
}
}
}
principal_validation¶
Validates Principal elements in resource policies and trust policies.
Severity: high (varies by issue type)
What It Checks¶
- Service Principal Wildcards (
critical): Detects dangerous{"Service": "*"}patterns - Wildcard Principals (configurable): Detects
Principal: "*"or{"AWS": "*"} - Blocked Principals: Validates against configurable blocked list
- Allowed Principals: Enforces whitelist when configured
- Principal Condition Requirements: Requires specific conditions for certain principals
- Service Principal Format: Validates AWS service principal format
Service Principal Wildcards (Critical)¶
The most dangerous pattern is {"Service": "*"} in trust policies, which allows any AWS service to assume a role.
{
"Effect": "Allow",
"Principal": { "Service": "*" },
"Action": "sts:AssumeRole"
}
This is flagged as critical because it creates an extremely permissive trust relationship. Any AWS service - including services you don't control - could potentially assume this role.
Note: NotPrincipal: {"Service": "*"} is NOT flagged because it means "everyone EXCEPT all services", which is an exclusion, not an overly permissive grant.
Wildcard Principal Handling¶
The check supports two modes for handling Principal: "*":
- Default mode (
block_wildcard_principal: false): Allows*if appropriate conditions are present (configured viaprincipal_condition_requirements) - Strict mode (
block_wildcard_principal: true): Blocks*entirely, regardless of conditions
When Wildcard with Conditions is Valid¶
Some use cases legitimately require Principal: "*" with conditions:
- S3 bucket policies with
aws:SourceArnandaws:SourceAccount - SNS topic policies for cross-account subscriptions
- Trust policies with
sts:ExternalIdfor confused deputy protection
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
},
"ArnLike": {
"aws:SourceArn": "arn:aws:s3:::source-bucket"
}
}
}
Configuration Options¶
principal_validation:
enabled: true
# Strict mode: block * entirely (default: false)
block_wildcard_principal: false
# Block {"Service": "*"} patterns (default: true)
block_service_principal_wildcard: true
# Explicit block list
blocked_principals:
- "arn:aws:iam::*:root"
# Whitelist mode (when set, only these are allowed)
allowed_principals:
- "arn:aws:iam::123456789012:*"
# Condition requirements for specific principals
principal_condition_requirements:
- principals: ["*"]
required_conditions:
any_of:
- condition_key: "aws:SourceArn"
- condition_key: "aws:SourceAccount"
Fail Examples¶
Critical - Service Principal Wildcard:
{
"Effect": "Allow",
"Principal": { "Service": "*" },
"Action": "sts:AssumeRole"
}
High - Wildcard without conditions (strict mode):
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*"
}
Medium - Missing required conditions (default mode):
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*"
}
How to Fix¶
For service principal wildcards - specify the service:
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
For wildcard principals - add conditions or specify principal:
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
}
}
}
mfa_condition_antipattern¶
Detects MFA condition anti-patterns that may not work as expected.
Severity: warning
Common Anti-Patterns¶
aws:MultiFactorAuthPresentin Deny withBoolIfExists- Missing MFA check with
StringEqualsinstead ofBool
not_action_not_resource¶
Detects dangerous NotAction/NotResource patterns that can grant overly broad permissions.
Severity: high
Why It's Dangerous¶
NotAction and NotResource grant permissions by exclusion rather than explicit inclusion. This means:
NotActionwithAllowgrants ALL actions except the listed onesNotResourcewithAllowgrants access to ALL resources except the listed ones
This makes it easy to accidentally grant more access than intended, especially as AWS adds new services and actions.
Patterns Detected¶
- NotAction with Allow (no conditions) - High: Near-administrator access
- NotAction with Allow (with conditions) - Medium: Still risky
- NotResource with broad Resource - High: Access to all resources except listed
- Combined NotAction AND NotResource - Critical: Near-administrator on nearly all resources
- NotAction with Deny - Low: Valid pattern but should be reviewed
When both NotAction and NotResource are present in an Allow statement, only the combined critical finding is reported. The individual NotAction and NotResource warnings are suppressed to reduce noise.
Implicit Grant Analysis¶
When NotAction is used with Allow, the check analyzes which service prefixes are excluded and explains what's implicitly granted. For example:
All AWS services EXCEPT
iam,stsare implicitly granted access.
This helps you understand the actual blast radius of NotAction patterns.
Fail Example¶
{
"Effect": "Allow",
"NotAction": ["iam:*", "sts:*"],
"Resource": "*"
}
This grants ALL AWS actions except IAM and STS. All AWS services EXCEPT iam, sts are implicitly granted access - equivalent to near-administrator access.
How to Fix¶
Replace NotAction with explicit Action lists:
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "dynamodb:Query"],
"Resource": [
"arn:aws:s3:::my-bucket/*",
"arn:aws:dynamodb:us-east-1:123456789012:table/my-table"
]
}
If NotAction is truly required, add strict conditions:
{
"Effect": "Allow",
"NotAction": ["iam:*", "sts:*"],
"Resource": "*",
"Condition": {
"Bool": { "aws:MultiFactorAuthPresent": "true" },
"IpAddress": { "aws:SourceIp": "10.0.0.0/8" }
}
}