No HTTP route returns personal data to a caller that has not been authenticated. 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) plus nginx, Terraform, serverless and CloudFormation files, analysed statically with the platform kit: tokens, function units, calls, imports and route registrations of Next (app and pages), Express, Fastify, Koa, Hono, Nest, Lambda, Django (views and urls.py), Flask, FastAPI and Laravel. A route returns personal data when the body it answers with — the arguments of res.json/send, NextResponse.json, Response.json, jsonify, JsonResponse, response()->json, a returned object literal, the initialiser of the variable it answers with, the select/values/only projection it reads, or the class body of a serializer, resource or DTO it references — names a strong personal-data field (e-mail, phone, first/last/full name, date of birth, national id, passport, tax id, address, postal code, IBAN, bank account, card number, salary, health, biometric, IP address, geolocation), or when it answers with a whole user/customer/member record read from the store without a projection. The authentication gate is searched on the route (middleware, decorator, guard, Laravel auth: middleware, login_required, permission_classes, Depends), on its class or controller (UseGuards, LoginRequiredMixin, permission_classes, $this->middleware honouring only/except), in the handler and the functions it calls within 2 module hops (requireAuth*, getServerSession, auth(), getSession*, verifyToken, jwt.verify, a service secret, req.user/request.user), in a gate registered earlier in the same file (app.use(auth) before the route), and framework-wide: a Next.js middleware or proxy whose matcher covers the route and whose route→strategy map does not declare it public (longest prefix wins; the default strategy applies to /api/*), app.use(auth) in an entry file, Nest APP_GUARD or useGlobalGuards, DRF DEFAULT_PERMISSION_CLASSES with IsAuthenticated (DRF views), Django login-required middleware, Laravel Kernel global middleware and api/web groups, FastAPI router dependencies. Paths listed in excludes are never analysed. Nothing of the checkout is executed.
Decision rule
Not applicable when no HTTP route is declared. Routes public by design (a login, logout, register, OAuth, callback, webhook, SSO segment; a short health/status/ping/version/metrics path) are excluded. FAIL (HIGH, unauthenticated-pii-endpoint) when a route returns personal data of other people (a resource parameter in the path, or a listing) and no authentication gate is found on the route, its class, the handler or its callees within 2 module hops, the same file, or the framework configuration. The same without a gate on an own-record route (a me, self, session, whoami, profile, account, current segment and no resource parameter) is MEDIUM (unauthenticated-own-record; blocks only in Extended suites). PASS when every route returning personal data is behind a gate (the summary names each route and the gate that covers it), or when no route returns personal data (the inventory is the evidence). Not judged by this check (declared): authorisation — whether the authenticated caller may read the specific record (idor, multi-tenant-isolation), the strength of the gate (an optional token, a spoofable header), and data that is public by design of the product (published profiles), which the source cannot state.
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. Routes are kit function units; personal data is decided on the answered body (response arguments, initialisers, projections, serializers and DTOs); the auth gate is searched on the route, its class, the handler and its callees (2 hops), app.use before the route, and framework-wide (Next.js middleware matcher plus route map, APP_GUARD, DRF defaults, Laravel Kernel). Other people's personal data without a gate is HIGH, an own-record route is MEDIUM. Not judged: authorisation (idor, multi-tenant-isolation). (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).)))
// a route is a FUNCTION UNIT of the static analysis kit (Next, Express, Fastify, Koa, Hono, Nest, Lambda, Django, Flask, FastAPI, Laravel)
// piiReturned(handler): PII_STRONG over the bodies the handler answers with (res.json/NextResponse.json args + the initialisers of the identifiers passed, `return {...}`, select/values projections, referenced serializers/DTOs)
// coverageOf(handler, 'auth'): route middleware/decorators -> class guards -> calls in the handler and its callees (<= 2 module hops) -> app.use(auth) before the route -> Next.js middleware matcher + route map / APP_GUARD / DRF defaults / Laravel Kernel
// PII returned and no gate anywhere -> HIGH (own-record route: MEDIUM); public-by-design routes excluded; no route -> not-applicable
The full script is disclosed on request in a read-only viewer (never published on GitHub); the attestation binds to this exact hash.