01 / The WHO-CAN Approach
Inverted Analysis
Traditional tools start from identities and list what they can do. Whocan inverts the question: start from your most critical assets and find every path that reaches them. This is how attackers think — they target resources, not policies.
Analysis flow
Input
Critical asset
S3 bucket, KMS key, secret, database
Analysis
Full-chain resolution
SCP → RCP → IbP → PB → RbP → Conditions
Result
Every principal with access
Users, roles, IC users, cross-account
Layers evaluated: SCPRCPIbPPBRbPConditions
Why it matters
Starting from resources reveals access paths that identity-first analysis misses: resource policies granting direct access, cross-account trust chains, and condition-dependent paths that only activate under specific circumstances.
Example queries
Who can read production secrets?
who-can(
action: "secretsmanager:GetSecretValue"
resource: secrets
)Who can decrypt with production KMS keys?
who-can(
action: "kms:Decrypt"
resource: var:prod-kms-keys
)
02 / Managed Policy Tracking
External Policies Evolution
Cloud providers silently update managed policies. When AWS adds a new action to AmazonBedrockLimitedAccess, every principal with that policy gains a new capability — without any action on your part. Your posture changes. You don't know.
Analysis flow
Input
AWS updates managed policy
New action added silently
Analysis
Catalog tracking
Updated catalog mapped against your policies
Result
Posture re-evaluation
All affected principals flagged
Layers evaluated: SCPRCPIbPPBRbPConditions
Why it matters
Static security frameworks update their action lists weeks or months after AWS. During that gap, your policies grant capabilities that no tool detects. Whocan stays current with AWS's action catalog and re-evaluates your policies without that lag.
Example queries
Who can create service-specific credentials?
who-can(
action: "iam:CreateServiceSpecificCredential"
)
03 / Wildcard Expansion Tracking
Service Evolution
A policy granting iam:Get* written in 2023 automatically covers every new Get action AWS adds in 2024-2026. When AWS launches a new service, existing wildcard policies like s3:* or bedrock:* silently match all its actions — including ones the policy author never anticipated.
Analysis flow
Input
AWS adds new action
bedrock:InvokeModelWithResponseStream
Analysis
Wildcard match detection
Existing bedrock:* policies now cover it
Result
Affected principals identified
New capability surfaced immediately
Layers evaluated: SCPIbPPBRbP
Why it matters
Every wildcard is a forward contract on future AWS actions. Whocan evaluates wildcards against the live action catalog, not a static list. When AWS adds bedrock:InvokeModelWithResponseStream, Whocan knows which policies already match it.
Example queries
Who can invoke any Bedrock action?
who-can(
action: "bedrock:InvokeModel"
resource: resources where self.Arn ~ /bedrock/
)
04 / Grant-Intent Divergence
Provenance Drift
Permissions accumulate. A role created for a narrow job grows wildcards, inherits group attachments, and acquires reach its author never approved. Provenance Drift compares a principal's current effective authority to the intent encoded at grant time — and surfaces the delta as a first-class result.
Analysis flow
Input
Grant-time baseline
Effective authority at creation or last review
Analysis
Divergence analysis
Current effective reach vs. recorded baseline
Result
Scope-creep findings
Principals whose effective authority exceeds intent
Layers evaluated: SCPIbPPBRbP
Why it matters
Quarterly access reviews catch obvious admins. They miss the slow accretion: a team membership added two quarters ago, a managed policy that grew an action, a permission boundary that was widened "temporarily". Provenance Drift makes that accretion visible as a continuous query, not an audit-week scramble.
Example queries
Principals whose effective reach diverges from baseline
users where self.Entitlements.Drift.size() > 0
map { Name, Arn, Drift: self.Entitlements.Drift }
05 / Transitive Access Graph
Lateral Movement
An attacker who compromises one identity doesn't stop there. They discover cross-account roles with broad trust policies, assume roles across accounts, and escalate privileges at each hop. A 3-hop chain — user to role A to role B to admin — is invisible to individual policy reviews.
Analysis flow
Input
Compromised identity
User, role, or IC user
Analysis
Transitive graph computation
All assume-role chains resolved
Result
Full blast radius mapped
Every reachable role and resource
Layers evaluated: SCPRCPIbPRbPConditions
Why it matters
Whocan computes the complete transitive assume-role graph across all accounts. Every chain is visible: user → role → role → admin. Including Identity Center sessions, cross-account trust, and service-linked role paths.
Example queries
Roles assumable by any AWS principal
roles where self.AssumeRoleStatement has (
self.Effect == "Allow"
& self.Principal includes "*"
)Cross-account role trust analysis
roles where self.AssumeRoleStatement has (
self.Effect == "Allow"
& self.Action includes "sts:AssumeRole"
) map { Name, Arn, AssumeRoleStatement }
06 / Dynamic Critical Sequences
Privilege Escalation
Most privilege escalation paths don't appear in security referentials. They are multi-step sequences where individually harmless permissions combine into admin access: PassRole + CreateFunction + InvokeFunction = escalation to any role. Whocan discovers these dynamically — not from a static checklist.
Analysis flow
Input
Individual permissions
iam:PassRole + lambda:CreateFunction + lambda:InvokeFunction
Analysis
Sequence detection
Multi-step chain computed dynamically
Result
Escalation paths flagged
Full path to admin or sensitive access
Layers evaluated: SCPIbPPBRbP
Why it matters
Security frameworks maintain static lists of "sensitive actions" updated weeks after AWS changes. Whocan computes critical sequences dynamically, discovering escalation paths that no predefined list contains.
Example queries
All privilege escalation sequences
users where self.Entitlements.Abilities includes "iam-privilege-escalation"
map { Name, Arn, Sequences: self.Entitlements.Sequences }Who can pass roles to Lambda?
who-can(
action: "iam:PassRole"
always-ok-vars: ["iam:PassedToService"]
)
07 / Attribute-Based Access Control
Application Segmentation
In a well-governed environment, App A's principals should never access App B's resources. Whocan validates workload boundaries using tag-based attribute control (ABAC): principals tagged team=platform shouldn't read buckets tagged app=payments. Cross-boundary violations are surfaced immediately.
Analysis flow
Input
Tagged principals & resources
team=X, application=Y, dp:include:network
Analysis
Cross-boundary evaluation
Tag conditions resolved across full stack
Result
Boundary violations surfaced
App A principals reaching App B resources
Layers evaluated: SCPRCPIbPPBRbPConditions
Why it matters
Data perimeter policies use tags like dp:include:network and dp:exclude:identity to scope controls. Whocan evaluates these conditions realistically, validating that your ABAC controls actually enforce the boundaries you intended — across SCPs, RCPs, identity policies, and resource policies.
Example queries
Cross-application bucket access
app-a-users = users where self.Tags has (
self.Key == "application" & self.Value == "app-a"
)
app-b-buckets = buckets where self.Tags has (
self.Key == "application" & self.Value == "app-b"
)
who-can(
among: app-a-users,
action: "s3:GetObject",
resource: app-b-buckets
)Environment isolation: dev vs. production
dev-users = users where self.account() in var:dev-accounts
prod-resources = buckets where self.account() in var:production-accounts
who-can(
among: dev-users,
action: "s3:GetObject",
resource: prod-resources
)
08 / Organization Boundary Enforcement
Data Perimeter
Can an external role or principal assume a role in your organization? Can data leave through a misconfigured resource policy? Whocan validates the three perimeter dimensions — identity, resource, and network — checking that only trusted identities access trusted resources from expected networks.
Analysis flow
Input
External principal
Account outside organization, third-party role
Analysis
Three-perimeter validation
Identity + Resource + Network boundaries
Result
External access paths detected
Unauthorized cross-boundary access flagged
Layers evaluated: SCPRCPIbPPBRbPConditions
Why it matters
Data perimeter controls rely on SCPs, RCPs, VPC endpoint policies, and resource policies working together. A gap in any layer creates an exfiltration path. Whocan evaluates all layers simultaneously, detecting external access paths that per-layer analysis misses.
Example queries
Roles assumable from outside the organization
roles where self.AssumeRoleStatement has (
self.Effect == "Allow"
& self.Principal includes "*"
)Cross-account KMS access
prod-keys = kms-keys where self.account() in var:production-accounts
cross-account-readers = who-can(
action: "kms:Decrypt"
resource: prod-keys
) where self.account() not in var:production-accounts
cross-account-readers
09 / ABAC Down to the Row
Data-plane Conditions
Most tools stop at "conditional access — we can't tell you who." Whocan materializes the runtime context with the env: parameter and evaluates condition keys that depend on it. The result is a concrete principal list, not a disclaimer.
Analysis flow
Input
Tenant or context to test
tenantId=tenant-a
Analysis
env: context materialization
Condition keys evaluated against the supplied context
Result
Resolved principal list
Exact access for the specific scenario, no disclaimers
Layers evaluated: SCPRCPIbPPBRbPConditions
Why it matters
Real multi-tenant isolation, per-customer encryption boundaries, and row-level access control all depend on condition keys that resolve at request time. A tool that returns "conditional access" cannot prove these boundaries hold. Whocan supplies the context explicitly and returns the actual answer — the same authorization decision AWS itself would make for that specific request.
Example queries
Multi-tenant object-tag isolation (S3)
tenant-id = "tenant-a"
who-can(
action: "s3:GetObject"
resource: var:multi-tenant-bucket
env: {"s3:existingobjecttag/tenantid": tenant-id}
)