No log statement, error-tracker call or analytics event in the payment flow writes a request body, a response body, a gateway object or card data. 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) whose path names the payment flow (pay, payments, checkout, billing, charge, invoice, subscription, webhook or a gateway) or whose code references a gateway. In them, every call to a sink — console.*, logger/log/logging/winston/pino/Log::*, print, error_log, var_dump, print_r, Sentry, sentry_sdk, Bugsnag, Rollbar, New Relic, Datadog, analytics track/identify/capture, PostHog, Mixpanel, gtag, Amplitude, Segment — is analysed from its real arguments (tokens: identifiers, members, object properties, spreads, serialisers, template-literal and f-string interpolations), never from the text of its string messages or the comments. 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 has no payment file. FAIL (HIGH, with the line of the argument) when a sink call in a payment file receives card data by name (cvv, cvc, cardNumber, card_number, pan, creditCard, securityCode as an identifier, member or key), or a WHOLE object named for the request body (req.body, request.data, request.json(), request.POST, $request->all(), $request->getContent()…), the response body (response.data, res.data…), a gateway object (payload, body, event, paymentIntent, intent, charge, invoice, checkoutSession, paymentMethod, card, webhookEvent, webhook, refund, transaction, setupIntent, event.data.object), handed over as an argument, an object property value, a shorthand property, a spread, a serialiser argument (JSON.stringify, json_encode, json.dumps, str, repr, print_r, dict), a string concatenation or formatting operand, or an interpolation. A whole object under a generic name (data, result, response, res, resp, session, customer, subscription, params, order, payment, tx, details, record, entity) is MEDIUM and blocks only inside Extended suites. A sink that is an error tracker or an analytics service is reported as payload-to-third-party (CWE-200). A scalar field of the object (intent.id, charge.status, event.type), an index (event['type']), a name that only appears inside a string message or a comment, an identifier, a status or an amount never counts. PASS when every sink call in the payment files hands over none of that. Not judged by this check (declared): objects passed to application-defined logging wrappers whose name is not a known sink, a spread or a serialisation of an object whose name is outside the vocabulary, an object reaching the sink through a helper or a variable renamed on the way, and what a generic-named object actually holds.
Type
deterministic
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 unit is the CALL to a sink; its real arguments are walked as tokens (whole-object references as argument, property value, shorthand, spread, serialiser, interpolation, concat/format operand); scalar-bound names (string parameters, .type/.id members, literals) are not payloads; the line is the argument's. Not judged: application-defined logging wrappers, spreads of unrecognised names, objects renamed on the way. (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).))
// the unit is the CALL to a sink (console/logger/logging/Log::/print/Sentry/Bugsnag/track/analytics/posthog/gtag), found with the static analysis kit
// its REAL arguments are walked as tokens: an identifier chain handed over whole (argument, property value, spread, serialiser, interpolation) is a reference
const EXPLICIT_ROOT = /^\$?(?:payload|body|event|paymentIntent|intent|charge|invoice|checkoutSession|paymentMethod|card|webhookEvent|webhook|refund|transaction)$/; // whole -> HIGH
const EXPLICIT_CHAIN = /^(?:req|request|\$request)\.(?:body|data|json\(\)|POST|form|all\(\)|getContent\(\))$|^(?:response|res|resp)\.(?:data|body)$/; // whole -> HIGH
const GENERIC_ROOT = /^\$?(?:data|result|response|res|session|customer|subscription|params|order)$/; // whole -> MEDIUM
// intent.id, event['type'], '[pay/webhook] received' (a string) -> nothing; no payment file -> 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.