Skip to main content

AWS IAM privilege-escalation graph builder and pathfinder for Non-Human Identities (roles, CI/CD pipelines, service accounts).

Project description

nhi-hunter

An AWS IAM privilege-escalation graph builder and pathfinder for Non-Human Identities — find the shortest path from a low-privilege role (a CI/CD pipeline, a service account) to Admin.

License: MIT Python 3.10+

⚠️ For authorized security testing only. Run it against an account you own or have explicit permission to assess. nhi-hunter only reads a local JSON dump — it never calls the AWS API and never assumes a role.


Why nhi-hunter?

Modern AWS accounts are full of Non-Human Identities (NHIs): CI/CD pipeline roles (GitHub Actions OIDC, GitLab runners), Lambda execution roles, cross-account automation roles. Each one has a permission policy and a trust policy — and the combination of the two, across many identities, can quietly chain together into a path from "deploy bot" to "AdministratorAccess".

nhi-hunter takes a local AWS IAM authorization-details dump (no live API calls, no credentials needed beyond the read-only export) and:

  1. Parses every role/user, its permission policies (inline + attached managed + group), and its trust policy.
  2. Builds a directed graph where an edge A -> B means "identity A can obtain the effective permissions of identity B", via:
    • sts:AssumeRole — A's policy allows assuming B, and B's trust policy allows A.
    • iam:PassRole + lambda:* — A can pass role B to a new/updated Lambda function and invoke it, running code as B.
  3. Finds the shortest path from a --start-role to any identity flagged as admin (AdministratorAccess/PowerUserAccess attached, or a wildcard Action: "*", Resource: "*" statement) and prints it as a readable attack tree.

V1 is intentionally narrow — full policy-evaluation completeness is already covered by mature tools like PMapper, Cloudsplaining, and Cartography. nhi-hunter is for the "give me a readable attack-path tree from this dump, right now" case — a quick purple-team check, or a CI gate on terraform plan output.


Quick start

pip install nhi-hunter

# Export your account's IAM data (read-only API call):
aws iam get-account-authorization-details > aws_iam_dump.json

nhi-hunter scan --input aws_iam_dump.json --start-role GitHubActionsOIDC
[*] Loaded 5 identities, 11 escalation edge(s)
[*] Admin/power-user targets: AdminRole, LambdaAdminRole
[*] Searching for escalation paths from 'GitHubActionsOIDC'...

ESCALATION PATH FOUND (1 hop(s)) -> LambdaAdminRole
GitHubActionsOIDC
  --[iam:PassRole + lambda:*]--> LambdaAdminRole

ESCALATION PATH FOUND (2 hop(s)) -> AdminRole
GitHubActionsOIDC
  --[iam:PassRole + lambda:*]--> LambdaAdminRole
  --[iam:PassRole + lambda:*]--> AdminRole

SCAN COMPLETE
┌────────────────────────┬───────┐
│ Metric                  │ Value │
├────────────────────────┼───────┤
│ Escalation paths found  │     2 │
│ Shortest path length    │     1 │
└────────────────────────┴───────┘

A multi-hop sts:AssumeRole chain looks like this (from the bundled example dump, --start-role CIRunner):

ESCALATION PATH FOUND (2 hop(s)) -> AdminRole
CIRunner
  --[sts:AssumeRole]--> DevRole
  --[sts:AssumeRole]--> AdminRole

(Note: once a role holds AdministratorAccess, it technically has iam:PassRole+lambda:*/sts:AssumeRole over every other identity too — this is why LambdaAdminRole and AdminRole show edges to/from each other in the example dump. The interesting result is the path into the first admin identity reached from your low-privilege starting role.)

nhi-hunter scan exits non-zero if any escalation path is found — usable as a CI gate on infrastructure changes.


Try it without an AWS account

examples/sample_iam_dump.json is a small, deliberately-misconfigured IAM dump (same data used in the test suite) with two escalation paths baked in: a 2-hop sts:AssumeRole chain (CIRunnerDevRoleAdminRole) and a 1-hop iam:PassRole + Lambda chain (GitHubActionsOIDCLambdaAdminRole).

nhi-hunter scan --input examples/sample_iam_dump.json --start-role CIRunner
nhi-hunter list-identities --input examples/sample_iam_dump.json

Console commands

nhi-hunter scan --input <file> --start-role <name> [options]   find escalation paths
nhi-hunter list-identities --input <file>                       list all identities + edges

Scan options:
  -i, --input            AWS IAM authorization-details JSON dump (required)
  -s, --start-role       identity (role or user) name to start from (required)
  -o, --output           write full results as JSON
      --aegistrace-url   report escalation paths to an AegisTrace instance
      --aegistrace-key   AegisTrace ingest API key

How the graph is built

Edge technique Condition MITRE ATT&CK
sts:AssumeRole A's policy allows sts:AssumeRole on B's ARN and B's trust policy allows A (by ARN, account root, or *) T1078.004 Valid Accounts: Cloud Accounts
iam:PassRole + lambda:* A's policy allows iam:PassRole on B's ARN and A can lambda:CreateFunction/UpdateFunctionCode/InvokeFunction T1078.004

An identity is flagged admin if it has AdministratorAccess or PowerUserAccess attached, has a statement granting Action: "*" on Resource: "*", or its name contains "admin"/"poweruser".

V1 limitations (documented, not silently swallowed):

  • Statements using NotAction/NotResource are skipped.
  • Condition blocks are ignored — a reported edge means "policy allows this", not "no condition would block it in practice".
  • Only identity-to-identity edges are modeled; resource policies (S3 bucket policies, Lambda resource policies, etc.) are not considered.

AegisTrace integration

AegisTrace's Identity Graph

  • Risk Engine models identities and relationships across an environment. Point nhi-hunter at a real account and report any discovered escalation paths directly:
nhi-hunter scan \
  --input aws_iam_dump.json \
  --start-role GitHubActionsOIDC \
  --aegistrace-url https://your-aegistrace-instance \
  --aegistrace-key $AEGISTRACE_INGEST_KEY

Discovered paths are POSTed to /api/ingest/nhihunter-event, creating AgentAction(agent_name="nhi-hunter") entries visible in AegisTrace's AI Action Approval Queue (/app/agent-security) — the same workflow used for mcp-aegis and prompt-fuzz findings.


Testing

pip install -e ".[dev]"
pytest

Companion projects

  • mcp-sploit — Metasploit-style exploitation framework for MCP servers (attacks the AI's tools).
  • prompt-fuzz — async LLM jailbreak/prompt-injection fuzzer (attacks the AI's brain).
  • AegisTrace — Trust OS that makes AI agent actions auditable and human-approved.
  • mcp-aegis — MCP security gateway; blocks dangerous tool calls by default.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nhi_hunter-0.1.0.tar.gz (13.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nhi_hunter-0.1.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file nhi_hunter-0.1.0.tar.gz.

File metadata

  • Download URL: nhi_hunter-0.1.0.tar.gz
  • Upload date:
  • Size: 13.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nhi_hunter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1bc5bae96eb4ade7c9d23e0a87e544681c4073a72c5bbb8be344df015887749d
MD5 af18afe7be36684d74a9ac2edecc6d69
BLAKE2b-256 8f7a616a35f10430c52269ad3588a435aaecf13776319d0272de5b5384b82fba

See more details on using hashes here.

File details

Details for the file nhi_hunter-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nhi_hunter-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nhi_hunter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 78164d9f6d21c94fa4d399a1973195239098707a2a9f3ba2aeadd272066b5b88
MD5 facccfe77d012c89169ac381e3c18fe6
BLAKE2b-256 b77a6813aabb114b99b0808724ddbcaca00a82dd39870990807fca7dad3a2e83

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page