Skip to content

Scrub secrets from error messages, stacks, and every outbound field - #27

Closed
sagnik11 wants to merge 1 commit into
mainfrom
fix/sdk-secret-scrubbing
Closed

sagnik11 wants to merge 1 commit into
mainfrom
fix/sdk-secret-scrubbing

Conversation

@sagnik11

@sagnik11 sagnik11 commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Why

Exception data is what reaches LLM-generated fixes, and it routinely carries secrets, for example:

  • connect ECONNREFUSED postgres://admin:hunter2@…
  • provider errors that echo API keys
  • ?token= in request URLs
  • cookies and bearer tokens in serialized headers

Until now, redaction only covered custom attributes, and in the browser only top-level emails. Everything else went to storage and the sink verbatim: messages, stack traces, span status messages, third-party spans, relayed browser events, and anything sent by older SDKs or plain OTel senders.

This is the SDK and ingester half of the runtime secret-scrubbing work. The backend half, which scrubs right before every LLM prompt, and the narrowing of the agents' org-DB access are in Autter-dev/autter-monorepo#325. Autter-dev/autter-monorepo#327 closes the Ask log-filter oracle.

What changed

SDKs. Scrubbing happens before anything leaves the customer's process, and it is on by default.

  • runtime-node scrubs:
    • exception messages, stacks and status messages in captureException/captureMessage, including the pre-init fallbacks;
    • process spans and withLlmCall/trackLlmCall errors;
    • LlmCallHandle.setAttributes and instrumentLlmClient.
  • runtime-node also adds:
    • a RedactingSpanExporter, so every exported span is scrubbed: HTTP URLs, headersToSpanAttributes, third-party instrumentations and app-level recordException;
    • scrubbing of relayed browser messages, stacks, names and nested context, with a new redact option;
    • a new redactText export.
  • runtime-browser scrubs messages, stacks, names and nested context. It adds a redact: { keys, values } | false option and a scrubText export. The bundle grows from 3.43 kB to 4.14 kB brotlied, within the 5 kB budget.
  • Python adapter: a new stdlib-only redact.py, used by the caught-exception sampler to scrub tracebacks.

Patterns

  • New value patterns:
    • Basic auth, and Authorization / Cookie / Set-Cookie header text;
    • connection strings with an empty user or @ in the password;
    • provider keys: sk-proj/sk-ant, Stripe, GitHub fine-grained, GitLab, npm, SendGrid, Google;
    • password= / ?token= / ?api_key= assignments;
    • Luhn-valid card numbers.
  • New sensitive keys: any *authorization header, session/sessionid/sid, pwd, dsn, and a bounded ssn match.
  • Custom value patterns now apply globally.
  • The email and URL-scheme quantifiers are now bounded. The email pattern was quadratic on long strings: about 1 s per 32 KB before, about 10 ms now.

Ingester. This is the second line of defence for old SDKs and third-party OTLP senders, before ClickHouse and before the sink that feeds LLM fixing.

  • It scrubs occurrence message, stack, route and errorType, span names, deep browser context and LLM-call attributes, using the shared patterns.
  • Extra patterns can be added via AUTTER_REDACT_VALUE_PATTERNS / AUTTER_REDACT_KEY_PATTERNS.

Parity: test-vectors/redaction.json runs against node, browser, the ingester and Python. CI now also runs the Python adapter tests.

Verification

All CI steps pass locally:

Step Result
npm run build passes
runtime-node tests 77/77
runtime-browser tests 40/40
otlp-ingester tests 101/101
size 4.14 kB / 5 kB
Python unittest 8 OK

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


View code changes stack in Autter

Summary

Summary generated by Autter.

Why this change

Secrets (tokens, keys, credentials, emails) could still reach telemetry storage and the sink through error messages, stack traces, and other free-text or attribute fields, including via the browser relay and ingester paths. This PR adds value-level scrubbing across every SDK and ingester outbound field instead of relying only on key-name matching.

What changes for users

Browser, Node, relay and ingester code now scrub secret-shaped values from messages, stacks, routes, context, LLM attributes and span data before they are sent, stored or forwarded. Operators can add custom scrub patterns via AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS, and a Python adapter plus shared test vectors keep implementations consistent.

Implementation and review notes

  • Ingester gets a new redact.ts (scrubText, scrubOccurrence, configureRedaction, isSensitiveKey), wired into normalize-browser.ts, normalize-otlp.ts, llm.ts, context.ts, and server.ts (scrubbing before fingerprinting). Review whether scrubbing before fingerprinting changes existing issue grouping, which the team rules treat as breaking.
  • config.ts adds patternListEnv, which parses the JSON pattern env vars and throws a plain new Error on invalid input at startup. This is deliberate fail-loud behaviour, but it matches a past review learning about untyped errors in this file.
  • Node SDK: redact.ts is substantially reworked, and a new redact-exporter.ts (RedactingSpanExporter) is wired in server.ts so span data is scrubbed at export. relay.ts and sanitizeBrowserPayload also apply scrubbing, addressing earlier findings about secrets under benign context keys.
  • Browser SDK (runtime-browser/src/index.ts) gains client-side scrubbing plus new options. Check this against the zero-dependency rule and the 5 KB brotli size budget enforced by npm run size.
  • New tests include redact.test.ts, e2e redaction tests, cross-language vectors in test-vectors/redaction.json, and Python tests run in CI. The fixtures contain credential-shaped literals that secret scanners flagged earlier, so confirm they are clearly fake.
  • Redaction regexes run on attacker-controlled strings. The ingester email pattern is bounded ({1,64}@...{1,253}), but verify all patterns in the new modules are linear-time and tolerate hostile inputs such as throwing proxies, per earlier ReDoS and trap findings.

Changes

Ingester (@autter/otlp-ingester)

  • Adds src/redact.ts as the single scrubbing module (scrubText, scrubOccurrence, configureRedaction, isSensitiveKey), with unit tests in src/redact.test.ts.
  • server.ts: calls configureRedaction(config) in createIngesterApp and scrubs occurrences before fingerprinting.
  • normalize-browser.ts: scrubs the route in bumpRollup, and the free-form context bag goes through the shared sanitiser.
  • normalize-otlp.ts and llm.ts: scrub OTLP free text and LLM attribute subsets via scrubText / isSensitiveKey.
  • context.ts: sanitizeRuntimeContext now reuses the shared redaction logic instead of its own copy (net -13 lines).
  • config.ts: adds redactValuePatterns / redactKeyPatterns to IngesterConfig, loaded from AUTTER_REDACT_VALUE_PATTERNS / AUTTER_REDACT_KEY_PATTERNS through a new patternListEnv helper. The helper validates each entry with new RegExp and throws at startup on invalid input.

Node SDK (@autter/runtime-node, @autter/runtime-next)

  • redact.ts: reworked value-level scrubbing with an expanded RedactOptions.
  • redact-exporter.ts (new): RedactingSpanExporter scrubs span data at export time, wired into initAutterServer in server.ts, with new AutterServerOptions fields.
  • relay.ts: sanitizeBrowserPayload and the relay handlers scrub message, stack, route and nested context values, including secrets under benign keys, before forwarding to the ingester. RelayOptions gains new options.
  • llm-instrument.ts: small adjustments so LLM span attributes pass through the redactor.
  • index.ts (runtime-node) and server.ts (runtime-next) export the new redaction surface.

Browser SDK (@autter/runtime-browser)

  • src/index.ts: client-side scrubbing of outbound event fields, with new AutterBrowserOptions fields. The README is updated.

Cross-language and tooling

  • adapters/python/redact.py and test_redact.py (new), plus caught_exceptions.py updated to use the redactor.
  • test-vectors/redaction.json: shared vectors consumed by the Python tests and runtime-browser/test/redact-vectors.test.mjs.
  • .github/workflows/ci.yml: adds python3 -m unittest discover -s adapters/python -v.
  • New and extended tests: runtime-node/test/redact.test.mjs, autoflush.test.mjs, fixtures/e2e-redaction.mjs, runtime-browser/test/redact-e2e.test.mjs.
  • Docs updated: CHANGELOG.md, docs/ARCHITECTURE.md, docs/CONTINUOUS-DETECTION.md, and the three package READMEs.

Breaking changes / compatibility notes

  • Fingerprints and issue grouping: scrubbing now runs before fingerprinting in server.ts. Messages, stacks or routes that previously contained secret-shaped values will hash differently, so some existing issues may regroup. The team rules treat fingerprint changes as breaking.
  • Startup behaviour: invalid AUTTER_REDACT_VALUE_PATTERNS / AUTTER_REDACT_KEY_PATTERNS (bad JSON, non-string entries, or invalid regex) now fail ingester startup. Unset variables behave as before.
  • Wire format: the /v1/browser version 1 payload and OTLP surface keep the same shape. Only field values are masked, and the new option fields are optional.

Acceptance Criteria

  • Secret-shaped values (bearer/basic tokens, JWTs, provider API keys, URL credentials, private-key blocks, emails) in error messages, stacks, routes, context, LLM attributes and span attributes are masked before leaving the browser SDK, Node SDK or relay, and again before ingester storage or sink forwarding.
  • A secret placed under a benign key (e.g. context.note) in a browser payload sent through sanitizeBrowserPayload or the relay handlers does not appear in the forwarded request or in ClickHouse.
  • The Node, browser and Python implementations produce identical results on every case in test-vectors/redaction.json.
  • AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS extend the built-in patterns, and invalid values fail startup with a clear message naming the variable.
  • Redaction never throws into host-app capture paths, including for circular structures and hostile inputs, and telemetry still fails open.
  • The browser bundle stays within the 5 KB brotli budget and has no new dependencies.
  • npm run build, the three package test suites, npm run size -w @autter/runtime-browser and the Python unittests pass in CI.
  • Ingest-behaviour change is covered by documented manual verification (see the test plan).

Test Plan

  • Run npm run build and confirm it passes.
  • Run npm run test -w @autter/runtime-node, npm run test -w @autter/runtime-browser and npm run test -w @autter/otlp-ingester.
  • Run npm run size -w @autter/runtime-browser and confirm the bundle is under 5 KB brotlied.
  • Run python3 -m unittest discover -s adapters/python -v and confirm the shared vectors in test-vectors/redaction.json pass.
  • Start the local stack (Docker Compose, ClickHouse on 8123, ingester on 4318). POST a /v1/browser version 1 payload whose message and stack contain a bearer token, a JWT and an email, and whose context has the same secrets under benign keys such as note and debug. Read the row back from runtime_error_occurrences and confirm none of the raw values are stored.
  • Send OTLP traces with an exception event, a gen_ai.* span and a url.path containing secret-shaped values. Confirm runtime_spans, runtime_llm_calls and runtime_metrics_1m rows hold masked values.
  • Start the ingester with AUTTER_REDACT_VALUE_PATTERNS='["internal-[0-9]{6}"]' and confirm a matching string is masked. Then set it to not-json and to ["("], and confirm startup fails with a message naming the variable.
  • With AUTTER_SINK_URL pointed at a local listener, confirm the forwarded batch carries scrubbed fields only.
  • In a Node app using initAutterServer, call captureException with an error whose message and attributes contain a secret, plus an object with a circular reference. Confirm the OTLP export is masked and the call does not throw.
  • Exercise createBrowserRelayHandler with a payload containing {context:{note:"sk-…"}} and confirm the forwarded request is masked.
  • Compare the fingerprint of an error with no secrets before and after this change, and confirm it is unchanged. For one containing a secret, confirm the regroup behaviour is understood.

Rollback Plan

  • Revert the merge commit on main. Re-run CI and republish the affected packages (@autter/runtime-node, @autter/runtime-browser, @autter/runtime-next, @autter/otlp-ingester) at a patch version. Applications can pin to the previous published versions in the meantime.
  • Ingester on AWS ECS Fargate: redeploy the previous ECS task definition revision (previous image tag in ECR) and roll the service.
  • Ingester on single-server: pin the previous ingester image tag in the compose file, pull it, and recreate only the ingester service. Do not touch the existing Caddyfile.
  • If only the operator-pattern parsing is the problem, unset AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS and restart. Built-in scrubbing remains active.
  • No ClickHouse schema or migration changes are included, so no database rollback is needed.
  • Rolling back restores the old fingerprints. Occurrences ingested while this change was live keep their masked values and new fingerprints, and these cannot be reverted. Expect issue regrouping in the consumer of the sink webhook in both directions.

Related Issues

No linked issue was identified from the branch name (fix/sdk-secret-scrubbing), commit context or diff.

Written for commit 7d936c6. Summary will update on new commits.

Exception data is what reaches LLM-generated fixes, and it routinely
carries secrets: `connect ECONNREFUSED postgres://admin:hunter2@…`,
provider errors echoing API keys, `?token=` in request URLs, cookies and
bearer tokens in serialized headers. Redaction previously covered only
custom attributes (and only top-level, email-only, in the browser), so
messages, stack traces, span status messages, third-party spans, relayed
browser events and anything an old SDK or plain OTel sender shipped went
to storage and the sink verbatim.

SDKs (scrub before anything leaves the customer's process, on by default):
- runtime-node: scrub exception messages/stacks/status messages in
  captureException/captureMessage (incl. pre-init fallbacks), process
  spans, withLlmCall/trackLlmCall errors, LlmCallHandle.setAttributes and
  instrumentLlmClient; add a RedactingSpanExporter so every exported span
  (HTTP URLs, headersToSpanAttributes, third-party instrumentations,
  app-level recordException) is scrubbed; relay scrubs browser
  message/stack/name/nested context (new `redact` option); new redactText
- runtime-browser: scrub messages, stacks, names and nested context; new
  `redact: { keys, values } | false` option and scrubText export
  (3.43 kB -> 4.14 kB brotlied, budget 5 kB)
- python adapter: new stdlib-only redact.py; caught-exception sampler
  scrubs tracebacks with it

Patterns: add Basic auth, Authorization/Cookie/Set-Cookie header text,
connection strings with empty user or `@` in the password, sk-proj/
sk-ant, Stripe, GitHub fine-grained, GitLab, npm, SendGrid, Google keys,
password=/?token=/?api_key= assignments, Luhn-valid cards; keys for any
*authorization header, session/sessionid/sid, pwd, dsn, bounded ssn.
Custom value patterns now apply globally. Email and URL-scheme
quantifiers are bounded (email was quadratic on long strings: ~1 s per
32 KB, now ~10 ms).

Ingester (second line of defence for old SDKs / third-party OTLP senders,
before ClickHouse and the sink that feeds LLM fixing): scrub occurrence
message/stack/route/errorType, span names, deep browser context and
LLM-call attributes with the shared patterns; extra patterns via
AUTTER_REDACT_VALUE_PATTERNS / AUTTER_REDACT_KEY_PATTERNS.

Parity: test-vectors/redaction.json runs against node, browser, ingester
and Python; CI now runs the Python adapter tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🤖 AI authorship

56.2% of changed code was AI-written — 0% human, 44% untracked, across 1,736 attributed line(s).

By model: claude:claude-opus-5-5 56%

Most AI-authored files:

  • packages/otlp-ingester/src/redact.test.ts — 100% AI (209 lines)
  • adapters/python/redact.py — 99% AI (196 lines)
  • test-vectors/redaction.json — 99% AI (194 lines)
  • packages/otlp-ingester/src/redact.ts — 98.3% AI (117 lines)
  • adapters/python/test_redact.py — 100% AI (111 lines)

Provenance measured at authorship time by the autter CLI.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🚦 Pre-merge checks · ⚠️ 8 warning, ✅ 195 passed

Needs attention

Check Status Explanation
Too many lines changed ⚠️ Warning This PR changes 1975 lines (limit 1000). Splitting into smaller, focused PRs makes review more reliable.
PII stored without application-level encryption ⚠️ Warning 3 potential issue(s) detected (max risk 87/100): CHANGELOG.md:8, packages/otlp-ingester/README.md:69, test-vectors/redaction.json:107.
Repetitive boilerplate (duplicated block) ⚠️ Warning 1 potential issue(s) detected (max risk 30/100): packages/otlp-ingester/src/normalize-browser.ts:74.
API key in source ⚠️ Warning 1 potential secret(s) detected (max risk 92/100): packages/runtime-node/test/fixtures/e2e-redaction.mjs:50.
Database connection URL with embedded credentials ⚠️ Warning 13 root-cause issue(s) detected (max risk 100/100): adapters/python/test_redact.py:52, test-vectors/redaction.json:6, test-vectors/redaction.json:51, test-vectors/redaction.json:61, test-vectors/redaction.json:103.
Co-change coupling ⚠️ Warning 2 file(s) changed without a partner they usually change with.
Code duplication / DRY violation ⚠️ Warning 1 finding(s) on changed lines.
Release Notes Curator ⚠️ Warning 1 potential issue(s) detected (max risk 33/100): packages/otlp-ingester/src/redact.ts:97.
✅ Passed checks (195)
Check Status Explanation
Too many files changed ✅ Passed Changed 32 file(s), within the limit of 50.
Too many unrelated chapters ✅ Passed 6 chapter(s) detected, within the limit of 6.
Generated files hiding real changes ✅ Passed Generated-file volume (0 lines) does not obscure the 1975 hand-written line(s).
Missing PR context ✅ Passed PR context looks sufficient.
Mixed concerns (refactor + behavior change) ✅ Passed The PR is one feature: secret scrubbing across the SDKs and the ingester. The edits to existing files (for example the context.ts deletions and the normalize-browser.ts rewiring) swap local redaction for the shared scrubber, which is part of that feature and is not a standalone no-behavior refactor. Tests, docs and ... [truncated 37 chars]
Migration + app logic + UI combined in one PR ✅ Passed The diff has no database migrations and no user-interface changes. It touches SDK and ingester logic, tests, docs and CI only.
Sensitive data in logs ✅ Passed No sensitive data in logs issues remaining after verification.
Log injection ✅ Passed No log injection issues detected.
Missing audit logging ✅ Passed No missing audit logging issues detected.
Removed observability ✅ Passed No removed observability issues remaining after verification.
Silent exception swallowing ✅ Passed No silent exception swallowing issues detected.
Unhandled promise rejection ✅ Passed No unhandled promise rejection issues detected.
Circuit breaker not detected ✅ Passed No circuit breaker not detected issues detected.
Stack trace leakage ✅ Passed No stack trace leakage issues detected.
Multi-write without detected transaction ✅ Passed No multi-write without detected transaction issues detected.
Possible TOCTOU in critical path ✅ Passed No possible toctou in critical path issues detected.
Idempotency key not detected ✅ Passed No idempotency key not detected issues remaining after verification.
Possible non-atomic read-modify-write ✅ Passed No possible non-atomic read-modify-write issues detected.
Optimistic locking not detected ✅ Passed No optimistic locking not detected issues remaining after verification.
Rate limiting not detected ✅ Passed No rate limiting not detected issues detected.
Rate limiting removed ✅ Passed No rate limiting removed issues detected.
Batch size limit not detected ✅ Passed No batch size limit not detected issues remaining after verification.
Pagination not detected ✅ Passed No pagination not detected issues detected.
Prompt injection risk ✅ Passed No LLM/AI-integration code touched by this diff.
LLM output used in a dangerous sink ✅ Passed No LLM/AI-integration code touched by this diff.
Sensitive data in prompt or system-prompt leakage ✅ Passed No LLM/AI-integration code touched by this diff.
Over-privileged LLM tool / excessive agency ✅ Passed No LLM/AI-integration code touched by this diff.
Missing validation on an LLM-driven decision ✅ Passed No LLM/AI-integration code touched by this diff.
Unbounded LLM usage (denial-of-wallet) ✅ Passed No LLM/AI-integration code touched by this diff.
Table exposed without row-level security ✅ Passed No row-level-security-related code touched by this diff.
Over-broad row-level security policy ✅ Passed No row-level-security-related code touched by this diff.
Code path that bypasses row-level security ✅ Passed No row-level-security-related code touched by this diff.
Privileged database credential reachable from the client ✅ Passed No row-level-security-related code touched by this diff.
Privileged query without row-level scoping ✅ Passed No row-level-security-related code touched by this diff.
Row-level security enabled with no policy ✅ Passed No row-level-security-related code touched by this diff.
Template-default gradient styling ✅ Passed No added frontend pages or design-slop markers in this diff.
Interchangeable AI marketing copy ✅ Passed No added frontend pages or design-slop markers in this diff.
Placeholder content shipped to users ✅ Passed No added frontend pages or design-slop markers in this diff.
Emoji standing in for an icon system ✅ Passed No added frontend pages or design-slop markers in this diff.
Call-to-action that goes nowhere ✅ Passed No added frontend pages or design-slop markers in this diff.
Templated page composition ✅ Passed No added frontend pages or design-slop markers in this diff.
Color outside the brand palette ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Hardcoded style bypassing design tokens ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Typography outside the brand type system ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
One-off UI instead of the shared component ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Copy that does not match brand voice ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Screen does not match the rest of the product ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Merge-blocking marker left in the change ✅ Passed No pending-work markers added by this diff.
Known-defect marker shipped in code ✅ Passed No pending-work markers added by this diff.
Untracked TODO without an issue reference ✅ Passed No pending-work markers added by this diff.
Test disabled or left pending ✅ Passed No pending-work markers added by this diff.
PII in logs ✅ Passed No pii in logs issues detected.
PII or internals leaked in error response ✅ Passed No pii or internals leaked in error response issues detected.
User data stored without retention controls ✅ Passed No user data stored without retention controls issues detected.
PII sent to external / cross-border destination ✅ Passed No pii sent to external / cross-border destination issues detected.
Lockfile resolution / integrity tampered ✅ Passed No lockfile resolution / integrity tampered issues detected.
Dependency runs install-time lifecycle script ✅ Passed No dependency runs install-time lifecycle script issues detected.
Possible dependency-confusion attack ✅ Passed No possible dependency-confusion attack issues detected.
Lockfile resolves a dependency the manifest does not declare ✅ Passed No lockfile resolves a dependency the manifest does not declare issues detected.
Checked-in build artefact modified without source change ✅ Passed No checked-in build artefact modified without source change issues detected.
Dockerfile build-step is insecure ✅ Passed No dockerfile build-step is insecure issues detected.
External artefact pulled in without integrity pinning ✅ Passed No external artefact pulled in without integrity pinning issues detected.
Changed export, importer not updated ✅ Passed No changed export with an un-updated importer detected.
Missing linked tracker issue ✅ Passed No missing linked tracker issue issues detected.
Missing CODEOWNERS reviewer approval ✅ Passed No missing codeowners reviewer approval issues remaining after verification.
Missing security-team review on sensitive path ✅ Passed No missing security-team review on sensitive path issues remaining after verification.
Source changes without matching tests ✅ Passed No source changes without matching tests issues detected.
Migration missing rollback / down step ✅ Passed No migration missing rollback / down step issues detected.
Frontend importing database client directly ✅ Passed No frontend importing database client directly issues detected.
Route handler bypassing service layer ✅ Passed No route handler bypassing service layer issues detected.
Backend service importing UI module ✅ Passed No backend service importing ui module issues detected.
Cross-context internals import ✅ Passed No cross-context internals import issues detected.
Workspace package rule violation ✅ Passed No workspace package rule violation issues detected.
Inconsistent logging pattern ✅ Passed No inconsistent logging pattern issues detected.
Inconsistent error handling ✅ Passed No inconsistent error handling issues remaining after verification.
Endpoint missing input validation ✅ Passed No endpoint missing input validation issues detected.
Multi-write without transaction wrapper ✅ Passed No multi-write without transaction wrapper issues detected.
New feature shipped without feature flag ✅ Passed No new feature shipped without feature flag issues detected.
Module placed in the wrong workspace package ✅ Passed No module placed in the wrong workspace package issues detected.
Hallucinated import (package not installed) ✅ Passed No hallucinated import (package not installed) issues remaining after verification.
Nonexistent package (not found in registry) ✅ Passed No nonexistent package (not found in registry) issues detected.
Call to function that does not exist ✅ Passed No call to function that does not exist issues detected.
Generic placeholder identifier in production logic ✅ Passed No generic placeholder identifier in production logic issues remaining after verification.
Overbroad try/catch swallowing all exceptions ✅ Passed No overbroad try/catch swallowing all exceptions issues detected.
TODO / FIXME on critical path ✅ Passed No todo / fixme on critical path issues detected.
Comment contradicts or fabricates code behaviour ✅ Passed No comment contradicts or fabricates code behaviour issues detected.
Abstraction defined but never used ✅ Passed No abstraction defined but never used issues detected.
Code style differs from rest of codebase ✅ Passed No code style differs from rest of codebase issues detected.
Established pattern ignored ✅ Passed No established pattern ignored issues detected.
Unhandled edge case (null / empty / zero / boundary) ✅ Passed No unhandled edge case (null / empty / zero / boundary) issues detected.
Insecure training-data / doc-example pattern ✅ Passed No insecure training-data / doc-example pattern issues detected.
Dead code (defined but never referenced) ✅ Passed No dead code (defined but never referenced) issues detected.
Deprecated API call ✅ Passed No deprecated api call issues detected.
API pattern from wrong library version ✅ Passed No api pattern from wrong library version issues detected.
API endpoint removed ✅ Passed No api endpoint removed issues detected.
HTTP method changed (GET ↔ POST etc.) ✅ Passed No http method changed (get ↔ post etc.) issues detected.
New required field added to request ✅ Passed No new required field added to request issues detected.
Field removed from response schema ✅ Passed No field removed from response schema issues detected.
Response field type changed ✅ Passed No response field type changed issues detected.
HTTP status code changed ✅ Passed No http status code changed issues detected.
Auth requirement added / removed / changed ✅ Passed No auth requirement added / removed / changed issues detected.
Error response shape changed ✅ Passed No error response shape changed issues detected.
Pagination behaviour changed ✅ Passed No pagination behaviour changed issues detected.
Outbound webhook payload schema changed ✅ Passed No outbound webhook payload schema changed issues detected.
GraphQL field removed without deprecation ✅ Passed No graphql field removed without deprecation issues detected.
GraphQL enum value removed ✅ Passed No graphql enum value removed issues detected.
Vendor API consumer ✅ Passed This PR does not touch call sites of an open vendor API change.
SQL injection ✅ Passed No sql injection issues detected.
Cross-site scripting (XSS) ✅ Passed No cross-site scripting (xss) issues detected.
Path traversal ✅ Passed No path traversal issues detected.
Command injection ✅ Passed No command injection issues detected.
Insecure deserialization ✅ Passed No insecure deserialization issues detected.
Weak cryptography ✅ Passed No weak cryptography issues detected.
Insecure randomness for security material ✅ Passed No insecure randomness for security material issues detected.
Unsafe file upload ✅ Passed No unsafe file upload issues detected.
Missing input validation ✅ Passed No missing input validation issues detected.
Unsafe CORS configuration ✅ Passed No unsafe cors configuration issues detected.
Unsafe / open redirect ✅ Passed No unsafe / open redirect issues detected.
Missing CSRF protection ✅ Passed No missing csrf protection issues detected.
Unsafe cookie / session settings ✅ Passed No unsafe cookie / session settings issues detected.
Sensitive data exposure ✅ Passed No sensitive data exposure issues detected.
Invisible Unicode / Trojan Source characters ✅ Passed No invisible unicode / trojan source characters issues detected.
Access token in source ✅ Passed No access token in source detected.
Cloud credential in source ✅ Passed No cloud credential in source detected.
Webhook signing secret in source ✅ Passed No webhook signing secret in source detected.
OAuth client secret in source ✅ Passed No oauth client secret in source detected.
JWT signing secret in source ✅ Passed No jwt signing secret in source detected.
Hardcoded password ✅ Passed No hardcoded password detected.
pull_request_target executes untrusted PR code ✅ Passed No pull_request_target executes untrusted pr code issues detected.
Repository secrets exposed to fork PRs ✅ Passed No repository secrets exposed to fork prs issues detected.
Overbroad GITHUB_TOKEN / pipeline permissions ✅ Passed No overbroad github_token / pipeline permissions issues detected.
Third-party action pinned by mutable tag ✅ Passed No third-party action pinned by mutable tag issues detected.
Shell injection via workflow expression ✅ Passed No shell injection via workflow expression issues detected.
Cache poisoning risk from fork PRs ✅ Passed No cache poisoning risk from fork prs issues detected.
Deployment workflow changed ✅ Passed No deployment workflow changed issues detected.
Environment protection rule weakened ✅ Passed No environment protection rule weakened issues detected.
Auth middleware removed from route ✅ Passed No auth middleware removed from route issues detected.
Route protection changed (protected → public) ✅ Passed No route protection changed (protected → public) issues detected.
Permission / RBAC check removed ✅ Passed No permission / rbac check removed issues detected.
Required role weakened ✅ Passed No required role weakened issues detected.
Admin-only route exposed to lower privilege ✅ Passed No admin-only route exposed to lower privilege issues detected.
Token validation skipped in middleware chain ✅ Passed No token validation skipped in middleware chain issues detected.
JWT verification weakened or changed ✅ Passed No jwt verification weakened or changed issues detected.
Session expiration / TTL changed ✅ Passed No session expiration / ttl changed issues detected.
Password reset flow changed ✅ Passed No password reset flow changed issues detected.
OAuth callback / redirect handling changed ✅ Passed No oauth callback / redirect handling changed issues detected.
Webhook endpoint missing signature verification ✅ Passed No webhook endpoint missing signature verification issues detected.
Public route touches private/PII data ✅ Passed No public route touches private/pii data issues detected.
Table dropped (data loss) ✅ Passed No table dropped (data loss) issues detected.
Column dropped (data loss) ✅ Passed No column dropped (data loss) issues detected.
Column type narrowed (truncation risk) ✅ Passed No column type narrowed (truncation risk) issues detected.
Constraint removed ✅ Passed No constraint removed issues detected.
Index dropped ✅ Passed No index dropped issues detected.
NULL → NOT NULL (backfill required) ✅ Passed No null → not null (backfill required) issues detected.
NOT NULL → NULL (constraint relaxed) ✅ Passed No not null → null (constraint relaxed) issues detected.
Column default changed ✅ Passed No column default changed issues detected.
Primary key changed (FK cascade risk) ✅ Passed No primary key changed (fk cascade risk) issues detected.
Foreign key changed ✅ Passed No foreign key changed issues detected.
Unique constraint removed (duplicate risk) ✅ Passed No unique constraint removed (duplicate risk) issues detected.
Enum value removed ✅ Passed No enum value removed issues detected.
Column renamed without compatibility alias ✅ Passed No column renamed without compatibility alias issues detected.
Table renamed without compatibility view ✅ Passed No table renamed without compatibility view issues detected.
Long-locking migration operation ✅ Passed No long-locking migration operation issues detected.
CREATE INDEX without CONCURRENTLY ✅ Passed No create index without concurrently issues detected.
CONCURRENTLY inside a transaction ✅ Passed No concurrently inside a transaction issues detected.
New enum value used in the same transaction ✅ Passed No new enum value used in the same transaction issues detected.
Foreign key added without NOT VALID ✅ Passed No foreign key added without not valid issues detected.
Foreign key column is not indexed ✅ Passed No foreign key column is not indexed issues detected.
Table created without a primary key ✅ Passed No table created without a primary key issues detected.
Timestamp without time zone ✅ Passed No timestamp without time zone issues detected.
Money stored as a float ✅ Passed No money stored as a float issues detected.
Volatile default rewrites the table ✅ Passed No volatile default rewrites the table issues detected.
CHECK constraint added without NOT VALID ✅ Passed No check constraint added without not valid issues detected.
Row-level security policy column is not indexed ✅ Passed No row-level security policy column is not indexed issues detected.
UNIQUE column still allows many NULLs ✅ Passed No unique column still allows many nulls issues detected.
CONCURRENTLY index is not retry-safe ✅ Passed No concurrently index is not retry-safe issues detected.
Frontend performance issue ✅ Passed No additional explanation was reported.
Frontend security issue ✅ Passed No additional explanation was reported.
Frontend correctness issue ✅ Passed No additional explanation was reported.
Accessibility issue ✅ Passed No additional explanation was reported.
Frontend maintainability issue ✅ Passed No additional explanation was reported.
Code correctness issue ✅ Passed No code correctness issue issues remaining after verification.
Runtime error risk ✅ Passed No runtime error risk issues remaining after verification.
Resource leak risk ✅ Passed No additional explanation was reported.
Data integrity risk ✅ Passed No additional explanation was reported.
Maintainability issue ✅ Passed No maintainability issue issues remaining after verification.
Redundant alias / duplicate import ✅ Passed No additional explanation was reported.
Redundant type construct ✅ Passed No additional explanation was reported.
Unnecessary type assertion ✅ Passed No additional explanation was reported.
Module smell ✅ Passed No additional explanation was reported.
Dead export (no callers) ✅ Passed No additional explanation was reported.
AI authorship ✅ Passed 56.2% AI-authored (claude:claude-opus-5-5: 56%), 0% human, 44% untracked.
Intent vs. implementation ✅ Passed The visible portion of the diff delivers the PR's central promise of scrubbing secrets from messages, stacks, span names, LLM fields and browser context in the ingester. The SDK-side work sits in files omitted from the digest, so it could not be checked. Requirements: 6 implemented. (Intent from PR description.)
Complexity Guard ✅ Passed No additional explanation was reported.
Bundle Size Monitor ✅ Passed No additional explanation was reported.

This comment is updated automatically whenever Autter reviews a new PR revision.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter posted 6 finding(s) as review threads below (🔴 4 · 🟠 2). Each carries a copy-paste AI fix prompt.

def test_nested_values_and_usage_counters(self):
out = redact_attributes(
{
"db": {"dsn": "postgres://u:p@h/db", "args": ["redis://:pw@cache:6379"]},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [deterministic] Hardcoded secret — Risk: 100/100

A Postgres connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is exploited it cascades to the downstream usage that depends on this file: dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `adapters/python/test_redact.py` around line 52, what looks like a real credential is committed in source. Move it to a secret manager / env var, rotate the leaked value, and add the pattern to `.gitleaks`/`detect-secrets` so it cannot land again. If this is genuinely test data, prefix the value with `EXAMPLE_` / `YOUR_KEY` or mock the credential. Blast radius — if this is exploited it cascades to the downstream usage that depends on this file: dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`, `packages/otlp-ingester/src/sink.test.ts`.

Flagged by Autter security & observability checks.

"text": [
{
"name": "JWT inside an error message",
"input": "invalid session eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c for user",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [deterministic] Hardcoded secret — Risk: 100/100

A JWT-shaped value appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is exploited it cascades to the downstream usage that depends on this file: dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `test-vectors/redaction.json` around line 6, what looks like a real credential is committed in source. Move it to a secret manager / env var, rotate the leaked value, and add the pattern to `.gitleaks`/`detect-secrets` so it cannot land again. If this is genuinely test data, prefix the value with `EXAMPLE_` / `YOUR_KEY` or mock the credential. Blast radius — if this is exploited it cascades to the downstream usage that depends on this file: dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`, `packages/otlp-ingester/src/sink.test.ts`.

Flagged by Autter security & observability checks.

// A process span whose thrown error carries a secret.
await autter
.withProcessSpan("nightly-sync", () => {
throw new Error("redis://:redispass99@cache:6379 refused");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [deterministic] Database connection URL with embedded credentials — Risk: 90/100

A Redis connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/test/fixtures/e2e-redaction.mjs` around line 42 a Redis connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`, `packages/otlp-ingester/src/sink.test.ts`..

Flagged by Autter security & observability checks.

await autter
.withLlmCall({ provider: "openai", model: "gpt-x" }, (llm) => {
llm.setAttributes({ "gen_ai.request.api_key": "should-not-leak", note: "ok" });
throw new Error("401 Incorrect API key provided: sk-proj-abcdefghijklmnopqrstuvwxyz0123");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [deterministic] API key in source — Risk: 90/100

A generic api key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/test/fixtures/e2e-redaction.mjs` around line 50 a generic api key is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Revoke the leaked token on the provider console, mint a replacement scoped to the minimum permissions you need, and audit recent provider-side activity. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`, `packages/otlp-ingester/src/sink.test.ts`..

Flagged by Autter security & observability checks.

request: { headers: { authorization: "Bearer abcdefghijklmnop123" }, url: "/cb?access_token=tok123456" },
});
captureMessage("payment for ORD-12345 used token eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.SflKxwRJSMeKKF2QT4fwpM");
listeners.get("unhandledrejection")({ reason: new Error("redis://:cachepw@cache:6379 down") });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Database connection URL with embedded credentials — Risk: 69/100

A Redis connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-browser/test/redact-e2e.test.mjs` around line 35 a Redis connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`, `packages/otlp-ingester/src/sink.test.ts`..

Flagged by Autter security & observability checks.


test("secrets inside nested string values are scrubbed, not just keys", () => {
const out = redactAttributes({
job: { args: ["--db", "postgres://u:pw123@db/x"], note: "Cookie: a=b" },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Database connection URL with embedded credentials — Risk: 69/100

A Postgres connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/test/redact.test.mjs` around line 318 a Postgres connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`, `packages/otlp-ingester/src/sink.test.ts`..

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🧭 PR hygiene & process suggestions

Autter has 1 suggestion(s) about the shape of this PR (size, scope, reviewability). These are process guidance — not code defects — so they are consolidated here instead of posted as inline comments on individual files.

🟠 PR changes too many lines — split it — Risk: 73/100

This PR changes 1975 lines (limit 1000). Largest contributors: packages/otlp-ingester/src/config.ts (24 lines), packages/otlp-ingester/src/normalize-otlp.ts (5 lines), packages/otlp-ingester/src/normalize-browser.ts (32 lines). Smaller, focused PRs are reviewed more reliably. Blast radius — if a regression hides in this large diff it cascades: functions intEnv, parseIngestKeys, loadConfig, IngesterConfig, sanitizeBrowserPayload, extractLlmCall, normalizeTraces, createBrowserRelayFetchHandler; scopes @autter/otlp-ingester; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/server.sink.test.ts, packages/otlp-ingester/src/sink.test.ts.

References:

🛠 AI fix prompt (copy & paste into your coding agent)
Reduce the diff size of this PR. Move unrelated changes to follow-up PRs and prefer a chain of small, sequential PRs over one large one.
Start with `packages/otlp-ingester/src/config.ts` — see if it can land as its own PR or be split along clear boundaries (e.g. one PR per public API change).
Target: total changed lines well under 1000.

References:
https://google.github.io/eng-practices/review/developer/small-cls.html
https://bssw.io/items/google-guidance-on-code-review

Flagged by Autter PR-hygiene checks.


💡 7 suggestion(s) — conventions, hardening and hygiene, not defects

Inline comments are reserved for concrete defects. These are things worth knowing that the diff does not prove wrong — a missing hardening layer, a convention the repo usually follows, a file that historically changes alongside one you touched. Skim, adopt what fits, ignore the rest.

  • 🔴 PII stored without application-level encryption (risk 100/100) — test-vectors/redaction.json:107
  • 🔴 PII stored without application-level encryption (risk 87/100) — packages/otlp-ingester/README.md:69
  • 🔴 PII stored without application-level encryption (risk 85/100) — CHANGELOG.md:8
  • 🟠 packages/runtime-next/src/index.ts usually changes with this file (risk 55/100) — packages/runtime-node/src/index.ts:34
  • 🟠 packages/otlp-ingester/src/types.ts usually changes with this file (risk 53/100) — packages/otlp-ingester/src/normalize-otlp.ts:2
  • 🟡 Code duplication / DRY violation (risk 25/100) — packages/otlp-ingester/src/normalize-otlp.ts:14
  • 🟡 Local email regex duplicates the central redact.ts scrubber (risk 20/100) — packages/otlp-ingester/src/normalize-browser.ts:74
⚠️ 1 unconfirmed finding(s) — flagged by a detector but not proven by Autter's verification pass

Inline comments are reserved for findings that survived verification. These are plausible but could not be confirmed from the available context, so they are listed here as FYIs instead — review the ones that look real to you.

  • 🟡 Configured regexes can block the ingester (risk 33/100) — packages/otlp-ingester/src/redact.ts:97 — The extra patterns come only from operator-controlled env config (AUTTER_REDACT_VALUE_PATTERNS / AUTTER_REDACT_KEY_PATTERNS), not from telemetry senders. An attacker cannot choose the regex. The risk only materializes if an operator deploys a pathological pattern, which makes it a configuration hazard rather than a reachable defect. Nothing here validates or time-bounds the patterns, so it is plau
🔕 1 finding(s) muted by prior team feedback

Your team previously dismissed or reacted 👎 to findings of the same type on these files, so Autter kept them out of inline comments. Listed here in case circumstances changed.

  • 🟡 Batch size limit not detected (risk 1/100) — packages/runtime-node/src/redact.ts:124

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🤖 Release Notes Curator

Impact: minor. This adds new user-facing options and exports (redact option, scrubText, redactText, Python redact.py, and the ingester's AUTTER_REDACT_* settings). It also widens secret scrubbing by default, and nothing in the public API is removed.

Changelog entry

Security: secrets and personal data are now scrubbed from error messages, stack traces and all outbound telemetry

Autter Runtime now masks secrets and personal data in exception messages, stack traces and span status messages. Before, it only masked custom attributes. This covers database connection strings, API keys and tokens, Authorization/Cookie headers, ?token=-style URL parameters, emails and card numbers. Every span is scrubbed again just before it is exported, so third-party instrumentation and your own recordException calls are covered too. The browser SDK, the browser relay, the Python adapter and the ingester apply the same rules. The ingester scrubs again before storage and before the sink webhook, so older SDKs and plain OpenTelemetry senders are covered as well.

New options:

  • The browser SDK has a redact option and a scrubText export.
  • The Node SDK exports redactText.
  • The Python adapter ships a new redact.py.
  • The ingester accepts AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS for your own patterns.

Heads-up: error messages that contained secrets are now grouped by their scrubbed text. Existing issues may regroup once, where before they split per secret value.

Custom agent · runs after review · configured in Autter

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter posted 6 finding(s) as review threads below (🟠 6). Each carries a copy-paste AI fix prompt.

occurredAt: Date,
counts: { requestCount?: number; errorCount?: number; sessionCount?: number },
): void {
route = scrubText(route);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Biome: lint/style/noParameterAssign — Risk: 55/100

Reassigning a function parameter is confusing.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/noParameterAssign` issue at packages/otlp-ingester/src/normalize-browser.ts:111: Reassigning a function parameter is confusing.

Flagged by Autter security & observability checks.


test("sensitive keys are masked at any depth; safe keys survive", () => {
for (const key of vectors.keys.sensitive) {
const out = sanitizeRuntimeContext({ outer: { list: [{ [key]: "raw" }] } }) as any;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Biome: lint/suspicious/noExplicitAny — Risk: 55/100

Unexpected any. Specify a different type.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/suspicious/noExplicitAny` issue at packages/otlp-ingester/src/redact.test.ts:37: Unexpected any. Specify a different type.

Flagged by Autter security & observability checks.

before(async () => {
chStub = createServer((req, res) => {
let body = "";
req.on("data", (chunk) => (body += chunk));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Biome: lint/suspicious/noAssignInExpressions — Risk: 55/100

The assignment should not be in an expression.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/suspicious/noAssignInExpressions` issue at packages/otlp-ingester/src/redact.test.ts:74: The assignment should not be in an expression.

Flagged by Autter security & observability checks.

attributes: [
str("exception.type", "OperationalError"),
str("exception.message", `stripe rejected ${STRIPE} for jane@example.com`),
str("exception.stacktrace", 'Traceback (most recent call last):\n File "/app/pay.py", line 9, in charge\n stripe.api_key = "' + STRIPE + '"\nOperationalError: password=hunter3py'),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Biome: lint/style/useTemplate — Risk: 55/100

Template literals are preferred over string concatenation.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useTemplate` issue at packages/otlp-ingester/src/redact.test.ts:163: Template literals are preferred over string concatenation.

Flagged by Autter security & observability checks.

const digits = value.replace(/\D/g, "");
let sum = 0;
for (let i = 0; i < digits.length; i++) {
let d = +digits[digits.length - 1 - i]!;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Biome: lint/style/noNonNullAssertion — Risk: 55/100

Forbidden non-null assertion.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/noNonNullAssertion` issue at packages/runtime-browser/src/index.ts:151: Forbidden non-null assertion.

Flagged by Autter security & observability checks.

if (custom === false) return value;
let out = String(value)
.replace(SECRET_RE, MASK)
.replace(HEADER_RE, "$1" + MASK)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Biome: lint/style/useTemplate — Risk: 55/100

Template literals are preferred over string concatenation.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useTemplate` issue at packages/runtime-browser/src/index.ts:168: Template literals are preferred over string concatenation.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter posted 7 finding(s) as review threads below (🟡 7). Each carries a copy-paste AI fix prompt.

Comment thread CHANGELOG.md

### Security

- Scrub secrets and PII from exception messages, stack traces and span status messages, not only custom attributes; re-scrub every span at export so third-party instrumentations, HTTP URLs (`?token=`) and `recordException` calls are covered; scrub `LlmCallHandle.setAttributes`, `instrumentLlmClient` attributes and provider errors, and module-level captures made before `initAutterServer` (`runtime-node`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 407

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at CHANGELOG.md:7: Line length: Expected: 80; Actual: 407

Flagged by Autter security & observability checks.

| `CLIENT_RATE_LIMIT_PER_MINUTE` | `120` | Per-key fixed window (client keys) |
| `OCCURRENCE_TTL_DAYS` / `SPAN_TTL_DAYS` / `METRICS_TTL_DAYS` | `14` / `7` / `90` | ClickHouse TTLs (applied at table creation) |
| `LLM_CALL_TTL_DAYS` | `90` | Retention for `runtime_llm_calls` rows |
| `AUTTER_REDACT_VALUE_PATTERNS` | — | JSON array of extra regex sources masked in stored/forwarded text and attribute values (built-in secret/PII patterns always apply) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 171

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at packages/otlp-ingester/README.md:69: Line length: Expected: 80; Actual: 171

Flagged by Autter security & observability checks.

const HEADER_VALUE_RE =
/((?:^|[^\w-])(?:proxy-)?(?:authorization|(?:set-)?cookie)["']?\s*[:=]\s*["']?)[^"'\r\n]+/gim;
const SECRET_ASSIGNMENT_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/otlp-ingester/src/redact.ts:29:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/otlp-ingester/src/redact.ts:29: packages/otlp-ingester/src/redact.ts:29:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

| `setContext(ctx)` | Attached to subsequent events |
| `flush()` | Force-send the queue (also runs on page hide/unload) |
| `redactContext(ctx)` | Mask obvious PII in a context bag (applied to every event automatically) |
| `redactContext(ctx)` | Mask secrets/PII in a context bag, nested (applied to every event automatically) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 107

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at packages/runtime-browser/README.md:85: Line length: Expected: 80; Actual: 107

Flagged by Autter security & observability checks.

const HEADER_RE =
/((^|[^\w-])(proxy-)?(authorization|(set-)?cookie)["']?\s*[:=]\s*["']?)[^"'\r\n]+/gim;
const ASSIGN_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/runtime-browser/src/index.ts:141:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/runtime-browser/src/index.ts:141: packages/runtime-browser/src/index.ts:141:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

* by `=` or `:`. Value ends at a delimiter so the surrounding query string
* or JSON stays readable. */
const SECRET_ASSIGNMENT_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/runtime-node/src/redact.ts:106:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/runtime-node/src/redact.ts:106: packages/runtime-node/src/redact.ts:106:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

if (options === false) {
return (attributes) => ({ ...(attributes ?? {}) });
const passthrough = ((attributes?: Attributes | null) => ({
...(attributes ?? {}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] oxlint: unicorn(no-useless-fallback-in-spread) — Risk: 30/100

packages/runtime-node/src/redact.ts:499:4: Empty fallbacks in spreads are unnecessary

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `unicorn(no-useless-fallback-in-spread)` issue at packages/runtime-node/src/redact.ts:499: packages/runtime-node/src/redact.ts:499:4: Empty fallbacks in spreads are unnecessary

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter posted 4 finding(s) as review threads below (🟠 4). Each carries a copy-paste AI fix prompt.

// Customer-supplied patterns extend the built-ins.
redact: { keys: /^internal_ref$/, values: [/ORD-\d{5}/g] },
});
setContext({ checkout: { cardNumber: "4111111111111111", step: "pay" } });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at packages/runtime-browser/test/redact-e2e.test.mjs:26. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

// Secrets inside exception messages, stacks, and status messages.
for (const secret of [
"hunter2pg",
"4111 1111 1111 1111",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at packages/runtime-node/test/autoflush.test.mjs:98. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

autter.captureException(
new Error("connect ECONNREFUSED postgres://admin:hunter2pg@db.internal:5432/app"),
);
autter.captureMessage(`charge failed for card 4111 1111 1111 1111 key ${STRIPE}`, "warning");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at packages/runtime-node/test/fixtures/e2e-redaction.mjs:36. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

},
{
"name": "credit card numbers (Luhn-valid), spaced and plain",
"input": "charge 4111 1111 1111 1111 declined; amex 378282246310005",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at test-vectors/redaction.json:138. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-next/package.json:1 · build_failure

🟡 [deterministic] Build failed: @autter/runtime-next — Risk: 40/100

npm run build could not verify the @autter/runtime-next build in packages/runtime-next — this is not evidence that this PR breaks it.

What happened: The build failed because TypeScript cannot find the module '@autter/runtime-node' in src/server.ts.

How to fix: This looks like an incomplete install or missing lockfile. Ensure '@autter/runtime-node' is listed as a dependency in your package.json and run npm install to resolve the missing module.

Build output
DTS dist/client.d.cts 1.07 KB

src/server.ts(34,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.
src/server.ts(60,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.
src/server.ts(73,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.

Error: error occurred in dts build
    at Worker.<anonymous> (/tmp/autter-agentic-ySbVjn/node_modules/tsup/dist/index.js:1545:26)
    at Worker.emit (node:events:514:28)
    at MessagePort.<anonymous> (node:internal/worker:350:14)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:848:20)
    at MessagePort.<anonymous> (node:internal/per_context/messageport:23:28)
npm error Lifecycle script `build` failed with error:
npm error code 1
npm error path /tmp/autter-agentic-ySbVjn/packages/runtime-next
npm error workspace @autter/runtime-next@1.4.0
npm error location /tmp/autter-agentic-ySbVjn/packages/runtime-next
npm error command failed
npm error command sh -c tsup
🛠 AI fix prompt (copy & paste into your coding agent)
The @autter/runtime-next build (`npm run build` in `packages/runtime-next`) fails. The build failed because TypeScript cannot find the module '@autter/runtime-node' in src/server.ts. Fix: This looks like an incomplete install or missing lockfile. Ensure '@autter/runtime-node' is listed as a dependency in your package.json and run npm install to resolve the missing module.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-node/src/redact.ts:386 · code_correctness

🟠 [ai] Global custom key regexes intermittently skip sensitive keys — Risk: 50/100

additionalKeyPatterns accepts RegExp values, and toCaseInsensitive preserves their g/y flags; calling .test() on those stateful regexes advances lastIndex. Consequently, matching keys in a context such as {secret1: ..., secret2: ...} with /secret/g can alternate between redacted and unredacted, leaking values that the configured pattern matches. The browser's redact.keys path has the same stateful .test() behavior. Normalize key patterns to non-stateful flags or reset lastIndex before each test.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-node/src/redact.ts, packages/runtime-browser/src/index.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Ensure key-pattern matching is independent of prior calls: strip `g`/`y` flags when compiling key regexes (or reset lastIndex before every test) in both the Node redactor and browser redactor.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter posted 3 finding(s) as review threads below (🟠 2 · 🟡 1). Each carries a copy-paste AI fix prompt.

endTime: span.endTime,
status,
attributes: redactor.exported(span.attributes),
links: span.links,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [ai] [P1] Redact link and resource attributes before export — Risk: 60/100

The exporter wrapper is installed around the OTLP trace exporter, but redactSpan scrubs span attributes and event attributes while passing span.links and span.resource through unchanged. OpenTelemetry link attributes and resource attributes are serialized with the span, so secrets in either field bypass this last-line redaction and can leave the process from spans produced by third-party instrumentation. Scrub these nested attribute bags before forwarding them.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-node/src/server.ts, packages/runtime-node/src/redact-exporter.ts
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

for (const key in context) {
const value = context[key];
out[key] = SENSITIVE_KEY_RE.test(key)
out[key] = SENSITIVE_KEY_RE.test(key) || (custom && custom.keys && custom.keys.test(key))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [ai] [P1] Reset custom key regex state for each context key — Risk: 50/100

redact.keys accepts any RegExp, but this .test() call does not reset lastIndex. With a valid global/sticky key pattern, consecutive matching keys can alternate between matching and failing; the later sensitive value is then copied through scrubValue and queued for transmission unmasked. Reset the regex state for every key (or compile a non-global copy) so the browser capture path consistently honors configured key redaction.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-browser/src/index.ts
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

for (const span of spans) {
try {
scrubbed.push(redactSpan(span, redactor));
} catch {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [ai] Redaction failures silently discard spans as successful exports — Risk: 40/100

If redactSpan() throws for any span, this catch silently omits that span and continues; line 71 then exports only the shortened batch using the original result callback. When the remaining batch (including an empty batch) succeeds, the batch processor treats the export as successful and drops the original spans, so a redaction failure permanently loses telemetry without surfacing an export error or diagnostic. Preserve the fail-closed privacy behavior, but make the dropped-span failure observable and report the export as failed rather than allowing callers to believe the complete batch was exported.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-node/src/redact-exporter.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Keep un-scrubbed spans out of the exporter, but surface any redaction failure through the exporter result callback (or an explicit observable error/counter) so the batch is not acknowledged as a successful complete export. Ensure the error path does not leak the span contents.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor
⚠️ 1 unconfirmed finding(s) — flagged by a detector but not proven by Autter's verification pass

Inline comments are reserved for findings that survived verification. These are plausible but could not be confirmed from the available context, so they are listed here as FYIs instead — review the ones that look real to you.

  • 🟡 Custom redaction regexes can freeze the public browser-ingest endpoint (risk 35/100) — packages/otlp-ingester/src/redact.ts:97 — The AUTTER_REDACT_VALUE_PATTERNS entries are only syntax-checked in config.ts (new RegExp). They are run unbounded over request-controlled strings in scrubText, and the built-in patterns were bounded. However, the patterns come from operator-set env config, so exploitation needs the operator to configure a catastrophic regex. That makes it a hardening gap, not a directly reachable bug. The finding

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🧪 Autter test run

Autter checked 7d936c61.

This PR changes 26 source files. It ran the project's test command for the workspace this PR touched, because those suites are the fastest check that the change did not break existing behavior. It wrote 3 temporary tests for changed files that had no matching test, so the new behavior is still checked. It also executed 9 checks from the PR's test plan.

Targeted agent checks: Autter ran targeted checks against the files this PR changed — it executed uncovered test-plan items and, where a changed file had no matching test, wrote a temporary test to verify the new behavior.

Execution summary: 19 checks executed · 15 passed · 4 failed.

Why suites failed

  • @autter/otlp-ingester — npm run test: a module could not be resolved, so this is an environment problem, not a verdict on the change.
    First error: Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'zod' imported from /tmp/autter-agentic-ySbVjn/packages/otlp-ingester/src/normalize-browser.ts

Project test commands

Scope Command Result
@autter/otlp-ingester npm run test ❌ failed · 1s

Autter targeted verification

16 tests executed · 14 passed · 2 failed.

Critical feature verification

Could not run: no valid structured result (exit=0, hadFile=true);

Code-level simulations

Revision 7d936c61b2f6 · 564.4s · up to 2 scenarios in parallel

  • Scrub legacy browser and OTLP events before storage and sink forwarding — passed (code_diff, code_diff, spec)
    Source: packages/otlp-ingester/src/server.ts — const input = scrubOccurrence(raw);
    Source: packages/otlp-ingester/src/redact.test.ts — const everything = [...clickhouseBodies, ...sinkBodies].join("\n");
    Source: PR description — This is the second line of defence for old SDKs and third-party OTLP senders, before ClickHouse and before the sink that feeds LLM fixing.
    Ran: node '.autter/scratch/redaction-ingester.mjs'
    ✅ Neither the ClickHouse fake's received request bodies nor the sink fake's batches contain any raw test credentials, token fragments, email, or URL credentials.: expected All raw test credentials and identifying markers are absent from ClickHouse request bodies and sink batches.; observed ClickHouse request bodies: 49; sink batches: 2; raw marker count: 0; both forwarding paths observed: true (integration)
    ✅ Masked messages retain useful surrounding text and stack frames; non-sensitive context survives, and the numeric GenAI token counter remains present.: expected Useful surrounding message text and stack frames, benign context values, and numeric input-token usage survive scrubbing while sensitive text is masked.; observed forwarding observed: true; message text preserved: true; stack frames preserved: true; benign context preserved: true; input-token counter preserved: true; redaction marker observed: true (integration)
    ✅ Both endpoints complete using the configured test key and return their normal success response.: expected Browser returns HTTP 202 with a positive accepted count; OTLP traces returns HTTP 200 with partialSuccess.; observed browser status: 202, accepted response: true; OTLP status: 200, normal response: true (service)
  • Validate operator redaction patterns at ingester startup and use — failed (code_diff, code_diff, spec)
    Source: packages/otlp-ingester/src/config.ts — for (const source of parsed) new RegExp(source as string);
    Source: packages/otlp-ingester/src/redact.ts — extraValuePatterns = (options.redactValuePatterns ?? []).map(
    Source: PR description — Then set it to not-json and to ["("], and confirm startup fails with a message naming the variable.
    Ran: node '.autter/scratch/redaction-startup.mjs'
    ✅ The valid pattern is returned by loadConfig and masks the matching substring when used by the configured ingester redactor.: expected patterns=[internal-[0-9]{6}], scrubbed=before [redacted] after, and the app listens on an ephemeral port; observed exit=0; patterns=["internal-[0-9]{6}"]; scrubbed="before [redacted] after"; listening=true (integration)
    ❌ Each malformed or invalid-regex configuration fails before the app begins listening; capture stderr and verify the diagnostic identifies AUTTER_REDACT_VALUE_PATTERNS as requested by the verification hint.: expected Both subprocesses exit unsuccessfully before listening, and both stderr diagnostics name AUTTER_REDACT_VALUE_PATTERNS; observed malformed: exit=1, namesVariable=false, didNotListen=true; invalid regex: exit=1, namesVariable=false, didNotListen=true (integration)
    ✅ No subprocess proceeds as though an invalid extra pattern had been silently ignored.: expected Both malformed-configuration subprocesses terminate unsuccessfully instead of reaching a listening state; observed malformed: exit=1, didNotListen=true; invalid regex: exit=1, didNotListen=true (integration)
    Diagnosis could not complete: no valid structured result (exit=0, hadFile=true);
    Regression: Identical harness and assertions failed on revision e4e2f00.
    Indexed blast radius: 7 direct / 7 transitive dependents (indexed 2026-08-25T18:32:07.053Z).
  • Verify Node capture and foreign spans are scrubbed on OTLP export — execution incomplete (code_diff, code_diff, code_diff, spec)
    Source: packages/runtime-node/src/server.ts — new RedactingSpanExporter(
    Source: packages/runtime-node/src/redact-exporter.ts — this.inner.export(scrubbed, resultCallback);
    Source: packages/runtime-node/test/fixtures/e2e-redaction.mjs — foreign.recordException(new Error("upstream said password=foreignpw1 for x"));
    Source: PR description — a RedactingSpanExporter, so every exported span is scrubbed
    Ran: node '.autter/scratch/node-capture-foreign-spans.mjs'
    Could not complete: Error: Simulation did not emit exactly one completed assertion report. Harness infrastructure error: child process timed out
  • Exercise redaction regexes with hostile long strings — execution incomplete (code_diff, code_diff, code_diff, code_diff, spec)
    Source: packages/runtime-node/src/redact.ts — const MAX_SCRUB_CHARS = 64 * 1024;
    Source: packages/otlp-ingester/src/redact.ts — const EMAIL_RE = /[A-Z0-9.%+-]{1,64}@[A-Z0-9.-]{1,253}.[A-Z]{2,63}/gi;
    Source: packages/runtime-browser/src/index.ts — const EMAIL_RE = /[A-Z0-9.
    %+-]{1,64}@[A-Z0-9.-]{1,253}.[A-Z]{2,63}/gi;
    Source: adapters/python/redact.py — EMAIL = re.compile(r"[A-Z0-9.%+-]{1,64}@[A-Z0-9.-]{1,253}.[A-Z]{2,63}", re.I)
    Source: PR description — The email and URL-scheme quantifiers are now bounded. The email pattern was quadratic on long strings: about 1 s per 32 KB before, about 10 ms now.
    Ran: node '.autter/scratch/redaction-hostile.mjs'
    Could not complete: Error: Simulation did not emit exactly one completed assertion report. Harness infrastructure/startup error: Cannot access 'nextRequestId' before initialization
    Source unavailable: Production route aggregates are unavailable: Runtime queries are not configured. No retained production error patterns were available for this repository.
    Coverage limitation: No production runtime IDs or production patterns were supplied, so the plan uses only checkout code and the supplied PR description.
    Coverage limitation: The ingester persistence-path simulation uses a local ClickHouse-compatible HTTP stub and a local sink fake; it verifies produced request bodies and forwarding behavior, not real ClickHouse schema or server behavior.
    Coverage limitation: These are planned local code simulations only; no tests, external requests or database services were run.
    Coverage limitation: Scenario omitted because its source evidence could not be verified: Verify browser redaction at the outbound beacon boundary
    Coverage limitation: Scenario omitted because its source evidence could not be verified: Verify Python caught-exception sampling scrubs emitted tracebacks

Declared tests: 23 test file(s) found — 14 ran, 2 not observed in suite output, 7 did not run.

The project's command reported 8 of them. Autter ran the other 6 files one by one so every declared test has a verdict (6 passed, 0 failed).

"Did not run" means no test command that Autter executed covers the file, so nothing in it was checked. "Not observed" means a test command ran but never named the file in its output. A runner that stops at the first failure, shards its files, or prints only a summary produces this. Autter cannot confirm these tests ran, so it does not count them as passed. The @autter/otlp-ingester command failed here, so the files after the failure most probably never started.

⚠️ Test cases that did not run
  • ⛔ adapters/python/test_redact.py — no test suite covers this file; the runner command was not available in the test environment
  • ⛔ packages/runtime-browser/test/client-context.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-browser/test/csp-actions.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-browser/test/network.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-node/test/lifecycle.test.mjs (4 cases) — no test suite covers this file
  • ⛔ packages/runtime-node/test/logger-ingester.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-node/test/logger.test.mjs (2 cases) — no test suite covers this file
  • ❔ packages/otlp-ingester/src/fingerprint.test.ts (10 cases) — its suite (@autter/otlp-ingester) failed before it reported this file
  • ❔ packages/otlp-ingester/src/latency.test.ts (5 cases) — its suite (@autter/otlp-ingester) failed before it reported this file

Tests for this change

Autter ran the existing tests for 5 changed files, and it wrote 3 temporary tests for changed files that had none (3 passed, 0 failed).

Change coverage (is each changed file's behavior verified by a test?)

Changed file Related test Result
packages/otlp-ingester/src/redact.ts packages/otlp-ingester/src/redact.test.ts ✅ existing test passes
adapters/python/caught_exceptions.py adapters/python/test_redact.py ✅ existing test passes
adapters/python/redact.py adapters/python/test_redact.py ✅ existing test passes
packages/otlp-ingester/src/server.ts packages/otlp-ingester/src/redact.test.ts ✅ existing test passes
packages/otlp-ingester/src/config.ts packages/otlp-ingester/src/continuous-detection.test.ts ✅ no declared test — temporary test passed
packages/otlp-ingester/src/context.ts packages/otlp-ingester/src/redact.test.ts ✅ existing test passes
packages/otlp-ingester/src/llm.ts packages/otlp-ingester/src/redact.test.ts ✅ no declared test — temporary test passed
packages/otlp-ingester/src/normalize-browser.ts packages/otlp-ingester/src/normalize-browser.test.ts ✅ no declared test — temporary test passed
🤖 Coverage-check evidence

packages/otlp-ingester/src/redact.ts

adapters/python/caught_exceptions.py

adapters/python/redact.py

packages/otlp-ingester/src/server.ts

packages/otlp-ingester/src/config.ts

packages/otlp-ingester/src/context.ts

packages/otlp-ingester/src/llm.ts

packages/otlp-ingester/src/normalize-browser.ts

Temporary tests are written under .autter/scratch/ for verification only — they are never committed to the repository.

Test plan (from the PR description)

  • ❌ Run npm run build and confirm it passes. — agent execution observed the wrong behavior
  • ❌ Run npm run test -w @autter/runtime-node, npm run test -w @autter/runtime-browser and npm run test -w @autter/otlp-ingester. — npm run test in otlp-ingester failed.
  • ✅ Run npm run size -w @autter/runtime-browser and confirm the bundle is under 5 KB brotlied. — verified by agent execution
  • ✅ Run python3 -m unittest discover -s adapters/python -v and confirm the shared vectors in test-vectors/redaction.json pass. — verified by agent execution
  • ⬜ Start the local stack (Docker Compose, ClickHouse on 8123, ingester on 4318). POST a /v1/browser version 1 payload whose message and stack contain a bearer token, a JWT and an email, and whose context has the same secrets under benign keys such as note and debug. Read the row back from runtime_error_occurrences and confirm none of the raw values are stored. — No local stack run provided.
  • ⬜ Send OTLP traces with an exception event, a gen_ai.* span and a url.path containing secret-shaped values. Confirm runtime_spans, runtime_llm_calls and runtime_metrics_1m rows hold masked values. — No OTLP trace run provided.
  • ❌ Start the ingester with AUTTER_REDACT_VALUE_PATTERNS='["internal-[0-9]{6}"]' and confirm a matching string is masked. Then set it to not-json and to ["("], and confirm startup fails with a message naming the variable. — agent execution observed the wrong behavior
  • ✅ With AUTTER_SINK_URL pointed at a local listener, confirm the forwarded batch carries scrubbed fields only. — verified by agent execution
  • ✅ In a Node app using initAutterServer, call captureException with an error whose message and attributes contain a secret, plus an object with a circular reference. Confirm the OTLP export is masked and the call does not throw. — verified by agent execution
  • ✅ Exercise createBrowserRelayHandler with a payload containing {context:{note:"sk-…"}} and confirm the forwarded request is masked. — verified by agent execution
  • ✅ Compare the fingerprint of an error with no secrets before and after this change, and confirm it is unchanged. For one containing a secret, confirm the regroup behaviour is understood. — verified by agent execution
🤖 Agent-executed checks

❌ Run npm run build and confirm it passes.
Browser and Node packages built; ingester tsc failed (TS2307) because express, @clickhouse/client, and zod are unavailable, followed by implicit-any errors.

✅ Run npm run size -w @autter/runtime-browser and confirm the bundle is under 5 KB brotlied.
Size: 4.14 kB with dependencies, minified and brotlied; limit 5 kB.

✅ Run python3 -m unittest discover -s adapters/python -v and confirm the shared vectors in test-vectors/redaction.json pass.
Ran 8 tests in 0.004s — OK; shared text vectors and sensitive/safe key vectors passed.

❌ Start the ingester with AUTTER_REDACT_VALUE_PATTERNS='["internal-[0-9]{6}"]' and confirm a matching string is masked. Then set it to not-json and to ["("], and confirm startup fails with a message naming the variable.
Valid pattern masked internal-123456. Invalid inputs threw, but messages were 'Unexpected token o, "not-json" is not valid JSON' and 'Invalid regular expression: /(/: Unterminated group'; neither nam…

✅ With AUTTER_SINK_URL pointed at a local listener, confirm the forwarded batch carries scrubbed fields only.
Local sink listener received a batch from SinkForwarder; raw bearer token, email, and API-key values were absent and the redaction marker was present.

✅ In a Node app using initAutterServer, call captureException with an error whose message and attributes contain a secret, plus an object with a circular reference. Confirm the OTLP export is masked and the call does not throw.
Local OTLP collector received /v1/traces; captureException did not throw with circular context, all tested raw secrets were absent, and [redacted] appeared in the export.

✅ Exercise createBrowserRelayHandler with a payload containing {context:{note:"sk-…"}} and confirm the forwarded request is masked.
createBrowserRelayHandler returned 202; local forward listener received the request with context masked and raw token absent.

✅ Compare the fingerprint of an error with no secrets before and after this change, and confirm it is unchanged. For one containing a secret, confirm the regroup behaviour is understood.
Secret-free fingerprint was unchanged. Before scrubbing, two secret variants differed; after applying scrubOccurrence, they intentionally grouped to the same fingerprint.

⬜ items could not be verified automatically and still need a manual check.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter posted 1 finding(s) as review threads below (🟡 1). Each carries a copy-paste AI fix prompt.

@@ -0,0 +1,209 @@
import assert from "node:assert/strict";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [deterministic] Tests failed: @autter/otlp-ingester — Risk: 40/100

npm run test could not verify the @autter/otlp-ingester test suite in packages/otlp-ingester — this is not evidence that this PR breaks it.

What happened: The test runner fails with ERR_MODULE_NOT_FOUND because the 'zod' package cannot be resolved when src/normalize-browser.ts imports it; this looks like an incomplete install or a missing/undeclared dependency in the lockfile rather than a logic bug in the changed code.

How to fix: Run a clean install (e.g. delete node_modules and re-run npm install / the workspace install) so 'zod' is present, and confirm packages/otlp-ingester's package.json declares zod as a dependency with the lockfile updated accordingly; if zod is only needed at build time, check whether it should be a devDependency instead.

Test output
 separates distinct signals (0.78155ms)
✔ fingerprint groups per-value message variants into one issue (1.106467ms)
✔ normalizeStackFrames extracts golden frames for go (2.20812ms)
✔ fingerprint is stable across repeated ingestion for go (0.446163ms)
✔ fingerprint survives line-number drift across re-deploys for go (0.399426ms)
✔ different defects with the same message stay separate for go (0.372941ms)
✔ normalizeStackFrames extracts golden frames for rust (0.67163ms)
✔ fingerprint is stable across repeated ingestion for rust (0.427537ms)
✔ fingerprint survives line-number drift across re-deploys for rust (0.522181ms)
✔ different defects with the same message stay separate for rust (0.406966ms)
---
✔ wide event logs preserve nested context, stable IDs and native trace IDs (3.122218ms)
✔ OTLP protobuf logs are decoded with the standard field numbers (7.884131ms)
✔ serialized context and path queries are scrubbed and excess batches fail explicitly (53.209882ms)
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'zod' imported from /tmp/autter-agentic-ySbV…
🛠 AI fix prompt (copy & paste into your coding agent)
The @autter/otlp-ingester test suite (`npm run test` in `packages/otlp-ingester`) fails. The test runner fails with ERR_MODULE_NOT_FOUND because the 'zod' package cannot be resolved when src/normalize-browser.ts imports it; this looks like an incomplete install or a missing/undeclared dependency in the lockfile rather than a logic bug in the changed code. Fix: Run a clean install (e.g. delete node_modules and re-run npm install / the workspace install) so 'zod' is present, and confirm packages/otlp-ingester's package.json declares zod as a dependency with the lockfile updated accordingly; if zod is only needed at build time, check whether it should be a devDependency instead.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Autter product walk

Autter did not drive this change in a browser.

This PR changes a backend/API, but Autter could not find a start, dev, or run command for it, so it could not boot the service and exercise its endpoints. Autter ran targeted checks only. Add a start command (a start/dev script, or make it discoverable on the repo's "How to run this" tab), and Autter exercises the endpoints on the next push.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

.:1 · product_walk_failure

🟠 [deterministic] Product walk failed: pytest adapters/python/test_redact.py — Risk: 75/100

Planned command pytest adapters/python/test_redact.py failed after this PR.

The PR rewrites redaction logic across the OTLP ingester, node/browser runtimes, and the Python adapter, and ships a shared test-vector corpus. There is no server start command, so the change is exercised via the package test runners. I target the redaction-specific suites (not the whole repo) and lean on the shared vectors file, which is where boundary/unicode/oversized-payload cases and cross-im

Expected: Python adapter redaction tests pass against the same corpus. This is the separate-language port most prone to boundary divergence (unicode handling, regex anchoring) from the TS implementation.

Output: https://autter-app-storage.s3.ap-south-1.amazonaws.com/pr-review/Autter-dev/autter-runtime/27/7d936c61b2f6f744c248421028f4b05b48db6935/walk/fn-step-3.txt

1 attempt(s), 0 of 3 retries used.
Attempt 1: The command was run from adapters/python but references adapters/python/test_redact.py relative to that directory, so pytest cannot find the file. The only allowed command repeats the same invalid path, and no preparation is available.
AI found no recoverable setup correction

ERROR: file or directory not found: adapters/python/test_redact.py

🛠 AI fix prompt (copy & paste into your coding agent)
ERROR: file or directory not found: adapters/python/test_redact.py


Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Autter review completed — merge blocked

Autter completed its review and found at least one confirmed merge-blocking finding.

Autter blocked this PR: build; test; product_walk_failure; 1 confirmed correctness/runtime finding(s). See the findings below and the full PR review for details.

Other findings explain the additional warnings, but they did not independently block this PR.

The merge gate remains blocked until the confirmed finding is resolved.

Retry

Retrying reruns the review on the same commit. If the commit is unchanged, the same finding and block may be reproduced.

  • Click Retry review on the autter/review-gate check below, or
  • Comment @autter review on this PR

Autter will post a new comment when the retry starts.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autter blocked this PR: build; test; product_walk_failure; 1 confirmed correctness/runtime finding(s). See the findings below and the full PR review for details.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Autter task list

  • Make credential-shaped vectors in redaction.json clearly fake (test-vectors/redaction.json, packages/runtime-browser/test/redact-vectors.test.mjs, adapters/python/test_redact.py) - Replace the MongoDB, MySQL, Postgres URL, PEM private-key and JWT literals at lines 6, 51, 61, 103 and 148 of test-vectors/redaction.json with obviously fake placeholders, or build them from fragments at load time. Keep every vector's expected masked output identical across the Node, browser and Python consumers.
  • Remove hardcoded credential literals from Python and Node test fixtures (adapters/python/test_redact.py, packages/runtime-node/test/fixtures/e2e-redaction.mjs) - Replace the Postgres URL at line 52 of adapters/python/test_redact.py, the Redis URL at line 42 and the generic API key at line 50 of packages/runtime-node/test/fixtures/e2e-redaction.mjs with clearly fake or runtime-assembled values. The redactor must still match them, and the tests' assertions must still pass.
  • Fix failing pytest run of the Python redaction tests (adapters/python/test_redact.py, adapters/python/redact.py, test-vectors/redaction.json) - Reproduce the failure of pytest adapters/python/test_redact.py and fix the import path, shared test-vector loading or redactor behavior that causes it. Verify the tests also pass under python3 -m unittest discover -s adapters/python -v.

Generated from PR diff, blast radius, and context.

Issues found

  1. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:51 — A MongoDB connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast rad…
  2. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:61 — A MySQL connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radiu…
  3. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:103 — A PEM private key block appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is e…
  4. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:148 — A Postgres connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast ra…
  5. Database connection URL with embedded credentials · risk 100/100 · adapters/python/test_redact.py:52 — A Postgres connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this cre…
  6. Database connection URL with embedded credentials · risk 100/100 · test-vectors/redaction.json:61 — A MySQL connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this creden…
  7. Private key in source · risk 100/100 · test-vectors/redaction.json:103 — A private key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it casca…
  8. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:6 — A JWT-shaped value appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is exploi…
  9. Hardcoded secret · risk 100/100 · adapters/python/test_redact.py:52 — A Postgres connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast ra…
  10. API key in source · risk 90/100 · packages/runtime-node/test/fixtures/e2e-redaction.mjs:50 — A generic api key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it c…
  11. Database connection URL with embedded credentials · risk 90/100 · packages/runtime-node/test/fixtures/e2e-redaction.mjs:42 — A Redis connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this creden…
  12. Product walk failed: pytest adapters/python/test_redact.py · risk 75/100 · .:1 — Planned command pytest adapters/python/test_redact.py failed after this PR. The PR rewrites redaction logic across the OTLP ingester, node/browser runtimes, …

50 additional non-blocking finding(s) are available in the Autter review.

Also detected but not listed above: 55 finding(s) dismissed as likely false positives by verification — see the Autter review dashboard for their verdicts.

🛠 Fix options

Check one option and Autter will start a fix run for the unresolved issues above.

  • One PR with all unresolved fixes
  • One independent PR per unresolved issue

Checking a box triggers the fix run immediately — Autter comments back with the issues being fixed and the branch created for each.

@sagnik11

sagnik11 commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

Closing as superseded by #26, which contains this PR's commit plus the review fixes, and is now merged.

@sagnik11 sagnik11 closed this Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant