Users of an application that authenticates them can enrol a second factor (TOTP, WebAuthn/passkeys or an identity-provider MFA) and the login verifies it. No AI engine is involved: the verdict is reproducible from the source alone.
Inputs
Non-test code files of the checkout (JavaScript, TypeScript, Python, PHP), the dependency manifests, configuration and documentation (JSON, YAML, TOML, Terraform, Markdown) and templates (HTML, Blade, Twig, EJS, Handlebars, Pug), analysed statically with the static analysis kit: tokens, function units, calls, imports and route registrations of Next, Express, Fastify, Koa, Hono, Nest, Lambda, Django, Flask, FastAPI and Laravel. The gate is the application's own authentication (a unit that compares a password or hash, a credentials provider, a login route) or an identity provider. The mechanism is looked for as concrete units: a second-factor library imported in code or declared in a manifest; an enrolment unit (a route or function named setup/enable/enrol/register of 2fa/mfa/totp/webauthn/passkey, or one generating a secret, a provisioning URI or registration options); a verification unit (a call verifying a TOTP, HOTP, WebAuthn assertion, backup or recovery code); a 2FA gate (middleware or decorator requiring the factor); a user-facing entry (a component, page or template whose path or content names two-factor, 2FA, MFA, authenticator app, passkeys or verification codes); identity-provider MFA configured or documented. For every login unit (a function that verifies a password, or a login route reaching one) the verification is searched in the unit, in the functions it calls within 2 module hops, in its route middleware, or as a deferral to a challenge unit. Paths listed in excludes (test, spec and tmp files, __tests__, __mocks__, fixtures, test, tests and audit-scripts folders) are never analysed. Nothing of the checkout is executed.
Decision rule
Not applicable when the checkout implements no user authentication. FAIL (HIGH) when the application authenticates users and no second-factor mechanism exists in the checkout (no library, no enrolment or verification unit, no 2FA gate, no user-facing entry and no identity-provider MFA configuration). PASS when the identity provider has MFA configured or documented and the checkout has no own login unit (enrolment, verification and entry point are the provider's). Otherwise a mechanism that lacks a piece is MEDIUM (second-factor-incomplete; blocks in Extended suites), one finding per missing piece with the line of the strongest existing evidence: no enrolment unit; a login unit that never requires the factor (no verification in the unit or its callees within 2 module hops, no 2FA gate on the route, and no deferral — a pending state, an enabled flag or a secret lookup — to an existing challenge unit); no user-facing entry point. PASS when the mechanism, the enrolment, the verification on every login unit and the entry point are all found; the summary names each. Not judged by this check (declared): whether the second factor is mandatory by policy, whether the provider's tenant actually enforces the MFA it declares, whether the session is issued before the factor is verified (ordering inside the login unit), and verification on the login path when the checkout has no login unit (the password check lives elsewhere).
Type
deterministic
1.1.1: a callee whose root is a name that `Object.prototype` also carries (`build().toString()` tokenizes to the bare callee `toString`; also `constructor`, `valueOf`, `hasOwnProperty`) was looked up in the plain object that holds the imported names, so it resolved to the INHERITED FUNCTION instead of to nothing and the whole check died with "name.includes is not a function". Only a real binding counts now, and the name of a unit is always read as a string. Found on a 1 319-file checkout (2fa-available and session-expiry-rotation, 2026-09-24); the same line was in the 15 scripts that walk the call graph, so all fifteen ship the fix. (1.1.0: deterministic: the rule runs over the static analysis kit (tokens, function units, calls, imports, routes) with no AI engine; exact decisionRule and languages published; not-applicable with the reason when the checkout gives nothing to evaluate. The mechanism is the presence of concrete units (library import or manifest, enrolment unit, verification unit, 2FA gate, UI entry, provider MFA configuration), replacing what the model 'established': none is HIGH; a login unit (password check plus session write) that neither verifies nor defers to a challenge, no enrolment unit, or no UI entry is MEDIUM each. Not judged: a policy mandating the factor, tenant enforcement, ordering inside the login unit. (1.0.2: never analyses temporary files (*.tmp.*; spec.excludes follows AUDITOR_ANALYSIS_EXCLUDES). (1.0.1: never analyses test, spec, fixture and mock paths nor the auditor's own scripts (spec.excludes = AUDITOR_ANALYSIS_EXCLUDES); a fixture-looking secret (sk_test_, example, dummy) in real code is LOW, informative; every model call stays under the engine prompt cap (spec.promptMaxChars = AUDITOR_AI_PROMPT_MAX_CHARS): assess mode sends the candidate set in parts and aggregates the verdicts (a HIGH in any part is a FAIL, an unsatisfied part is a FAIL).)))
const SECOND_FACTOR_LIB = /^(?:otplib|speakeasy|otpauth|@simplewebauthn\/[\w-]+|fido2-lib|pyotp|django_otp|two_factor|webauthn|PragmaRX\\Google2FA|OTPHP)$/i; // an import specifier or a manifest dependency
// no library, enrolment unit, verification unit, gate, UI entry or provider MFA -> HIGH
// login unit (verifies a password) without VERIFY_2FA in <= 2 module hops, without a 2FA gate and without deferral to a challenge unit -> MEDIUM; no enrolment unit -> MEDIUM; no UI entry -> MEDIUM
The full script is disclosed on request in a read-only viewer (never published on GitHub); the attestation binds to this exact hash.