Skip to main content

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 (CIRunner → DevRole → AdminRole) and a 1-hop iam:PassRole + Lambda chain (GitHubActionsOIDC → LambdaAdminRole).

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

Metadata

Release files for nhi-hunter 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nhi-hunter 0.1.0
File Size Uploaded Provenance
nhi_hunter-0.1.0.tar.gz 13.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nhi-hunter 0.1.0
File Interpreter ABI Platform
nhi_hunter-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 26.8 kB

Release files / nhi_hunter-0.1.0.tar.gz

Download URL nhi_hunter-0.1.0.tar.gz
Size 13.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1bc5bae96eb4ade7c9d23e0a87e544681c4073a72c5bbb8be344df015887749d
BLAKE2b-256 checksum
How to use checksums
8f7a616a35f10430c52269ad3588a435aaecf13776319d0272de5b5384b82fba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / nhi_hunter-0.1.0-py3-none-any.whl

Download URL nhi_hunter-0.1.0-py3-none-any.whl
Size 13.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
78164d9f6d21c94fa4d399a1973195239098707a2a9f3ba2aeadd272066b5b88
BLAKE2b-256 checksum
How to use checksums
b77a6813aabb114b99b0808724ddbcaca00a82dd39870990807fca7dad3a2e83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Security for nhi-hunter 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page