Skip to content

fix(security): bug-report budget for non-members, retention sparing crawl reports - #715

Merged
fclairamb merged 12 commits into
mainfrom
security/scan-specs-2026-10-30
Oct 30, 2026
Merged

fclairamb merged 12 commits into
mainfrom
security/scan-specs-2026-10-30

Conversation

@fclairamb

@fclairamb fclairamb commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Specs filed from the daily security scans. Each spec is the tracker for its finding. This PR files the specs and implements Z1 and Z2.

Implemented by this PR (specs archived in specs/done/2026/10/)

Earlier scan specs (implemented, in specs/done/2026/10/)

  • Y1 (low): 2026-10-29-01-bug-report-upload-instance-budget.md. Anonymous bug-report screenshots were capped per org, not per instance, and never deleted. Fixed in fix(security): instance-wide budget and retention for anonymous bug-report screenshots #708; Z1 and Z2 are follow-ups.
  • X1 (high): 2026-10-28-01-pat-cannot-mint-sessions-or-sign-in-factors.md. A PAT could open sessions in its owner's other orgs and add sign-in factors. Fixed in fix(security): PAT org binding, subscribe throttle, invite lookup, SNMP secret #699.
  • X2 (medium): 2026-10-28-02-status-subscribe-throttle-and-keep-confirmed.md. Unthrottled subscribe confirm emails, and re-subscribing un-confirmed a subscriber. Fixed in fix(security): PAT org binding, subscribe throttle, invite lookup, SNMP secret #699.
  • X3 (medium on SaaS): 2026-10-28-03-invite-lookup-without-org-scan.md. Invite lookup scanned every org. Fixed in fix(security): PAT org binding, subscribe throttle, invite lookup, SNMP secret #699.
  • X4 (low): 2026-10-28-04-snmp-community-secret-field.md. The SNMP community was not a secret field. Fixed in fix(security): PAT org binding, subscribe throttle, invite lookup, SNMP secret #699.
  • V1 (medium): 2026-10-27-01-device-consent-phishing-guard.md. Device-flow consent phishing. Fixed in fix(security): device consent phishing guard and 2FA disable throttle #693.
  • W1 (low): 2026-10-27-02-disable-2fa-attempt-throttle.md. DELETE /auth/2fa had no attempt budget. Fixed in fix(security): device consent phishing guard and 2FA disable throttle #693.
  • U1 (low): 2026-10-26-02-ai-repair-hold-skips-param-only-secrets.md. The repair: auto hold applied only when the check's secrets map had a value. Fixed in fix(ai): hold every scheduled repair-auto run to its granted hosts #683.
  • S1 (medium): 2026-10-25-01-ai-repair-grant-dropped-by-reference-resolution.md. The repair grant was compared after ${…} references were resolved. Fixed in fix(ai): hold the repair: auto host grant when the script or env holds a reference #678; U1 closed the remaining gap.
  • R1 (medium): 2026-10-24-01-ai-repair-auto-apply-partial-runtime-host.md. repair: auto applied a candidate that kept a literal host and added one built at runtime. Fixed in feat(ai): hold auto-applied repairs to the previous version's hosts (+ scan specs) #663.
  • Q1 (medium): 2026-10-23-02-ai-loop-secret-relay-through-model.md. AI loops relayed an encoded secret through the model.
  • P1 (medium): 2026-10-22-01-ai-script-secret-host-guard-runtime.md. AI runs with real secrets were only host-checked by regex.
  • K1 (medium): 2026-10-20-01-sender-response-body-caps.md. Notification senders and RabbitMQ read responses uncapped.
  • J1 (medium): 2026-10-19-01-a2a-response-size-cap.md. A2A responses were read uncapped.
  • I1 (low): 2026-10-18-01-plugin-schema-file-ref.md. Plugin schema $ref could load local files.
  • G1/G2 (low): 2026-10-17-01-postgres-check-connection-config.md. Postgres conninfo escaping and fallback to the worker's PG* env.
  • F1: 2026-10-16-15-pat-cache-revocation.md. The PAT cache outlived revocation.
  • E1: 2026-10-16-14-totp-on-federated-sign-in.md. No TOTP on federated sign-in.
  • E2: 2026-10-16-13-atomic-auth-attempt-counters.md. Auth attempt counters were not atomic.
  • H3: 2026-10-16-12-mcp-tokens-rejected-on-rest.md. MCP OAuth tokens worked on REST.
  • H2: 2026-10-16-11-slack-signature-fail-closed.md. Slack signature check failed open.
  • T1 / M2 (high): 2026-10-16-10-discovery-scans-egress-guard.md. Discovery scans were outside the egress policy.
  • N4: 2026-10-16-09-js-check-nested-docker-guard.md. A JS docker sub-check bypassed the gate.
  • N3 (high): 2026-10-16-08-status-page-components-cross-org.md. Status-page components could be edited across orgs.
  • D2/D3 (high): 2026-10-16-07-guard-status-subscriber-and-publication-webhooks.md. Subscriber and publication webhooks were not guarded.
  • C3: 2026-10-16-06-accept-invite-existing-account.md. Accepting an invite logged in as an existing account.
  • C1: 2026-10-16-05-kubeconfig-exec-and-incluster.md. Kubeconfig exec and inCluster were allowed.
  • N2: 2026-10-16-04-mysql-dsn-injection.md. MySQL DSN injection.
  • N1: 2026-10-16-03-env-secret-reference-allowlist.md. No allowlist for ${env:} references.
  • C2/H1: 2026-10-16-02-token-purpose-separation.md. Purpose tokens were accepted as access tokens.
  • D1: 2026-10-16-01-microsoft-signin-unverified-email-linking.md. Microsoft nOAuth email linking.

What changed

  • Z1: a signed-in user who is not a member of the named org (and not a super admin) now spends the anonymous screenshot budget and needs a dispatch slot. Text-only reports still go through.
  • Z2: ListFilesByGroup and SumFileSizeByGroup only match topic-less files, so retention no longer purges crawl reports and they no longer use the screenshot quota.

Decided by autopilot

  • Z1 spec, open question (refuse a non-member with 403, or treat as anonymous?): treat as anonymous (recommended answer).

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fclairamb and others added 9 commits October 30, 2026 07:22
…and super admins

An authenticated report skipped the instance-wide anonymous screenshot
budget and the dispatch-slot requirement whatever org it named, so any
signed-in account could fill every org's report quota. Now only a member
of the named org, or a super admin, skips them; any other signed-in
report is admitted like an anonymous one and keeps its attribution.

Spec: specs/todos/2026-10-30-02-bug-report-authenticated-org-membership.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reports

ListFilesByGroup and SumFileSizeByGroup now match topic IS NULL only, so the
bug-report sweep no longer purges website crawl reports and they no longer
count toward the screenshot quota.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.76%. Comparing base (9bef875) to head (86f1862).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
server/internal/handlers/feedback/service.go 83.33% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #715   +/-   ##
=======================================
  Coverage   89.76%   89.76%           
=======================================
  Files        1297     1297           
  Lines      132272   132288   +16     
=======================================
+ Hits       118733   118750   +17     
+ Misses      13530    13529    -1     
  Partials        9        9           
Files with missing lines Coverage Δ
server/internal/app/server.go 92.02% <ø> (ø)
server/internal/db/postgres/postgres.go 94.93% <100.00%> (+<0.01%) ⬆️
server/internal/db/sqlite/sqlite.go 96.66% <100.00%> (+<0.01%) ⬆️
server/internal/handlers/feedback/handler.go 82.19% <100.00%> (+0.24%) ⬆️
server/internal/jobs/jobtypes/job_state_cleanup.go 88.60% <ø> (ø)
server/internal/handlers/feedback/service.go 88.40% <83.33%> (-0.37%) ⬇️

... and 22 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fclairamb
fclairamb merged commit d929999 into main Oct 30, 2026
34 checks passed
@fclairamb
fclairamb deleted the security/scan-specs-2026-10-30 branch October 30, 2026 19:04
fclairamb added a commit that referenced this pull request Oct 31, 2026
…-in factors (#728)

## What changed

- **AA1 (medium)**: a JS check now has a 64 MiB per-run memory budget on
the native builtins that allocate in one call (`repeat`, `padStart/End`,
`join`, `Array(n)`, `ArrayBuffer` and typed arrays, `fill`,
`Array.from`, and the length-driven `sort`, `toSorted`, `map`, `with`,
`toReversed`, `toSpliced`). A refused call throws a `RangeError` and the
worker keeps running. Spec:
`specs/done/2026/10/2026-10-31-01-js-checker-memory-budget.md`.
- **AA2 (low)**: turning on TOTP, registering a passkey and setting a
first password now need the current password (or, without one, a sign-in
within 10 minutes). `2fa/confirm` requires a `setupToken`, and a
`totp-enabled` notice email is sent. dash0 asks for the password first.
Spec:
`specs/done/2026/10/2026-10-31-02-sign-in-factor-enrollment-reauth.md`.

**Breaking API change**: `2fa/setup` and `passkeys/register/begin`
refuse a request without `currentPassword` on accounts with a password;
`2fa/confirm` needs `setupToken`. Sessions issued before this have no
sign-in time, so passwordless accounts must sign in again once.

Known gaps (not covered): string `+` doubling, `replaceAll`,
`JSON.stringify` and `TextEncoder` can still amplify; the long-term fix
is process isolation of check workers (separate spec).

## Earlier scan specs (implemented, in `specs/done/2026/10/`)

- **Z1 (low)**:
`2026-10-30-02-bug-report-authenticated-org-membership.md`. Signed-in
non-members skipped the bug-report screenshot budget. Fixed in #715.
- **Z2 (low)**:
`2026-10-30-03-report-retention-spares-crawl-reports.md`. The report
retention sweep also deleted website crawl reports. Fixed in #715.
- **Y1 (low)**: `2026-10-29-01-bug-report-upload-instance-budget.md`.
Anonymous bug-report screenshots were capped per org, not per instance,
and never deleted. Fixed in #708; Z1 and Z2 are follow-ups.
- **X1 (high)**:
`2026-10-28-01-pat-cannot-mint-sessions-or-sign-in-factors.md`. A PAT
could open sessions in its owner's other orgs and add sign-in factors.
Fixed in #699.
- **X2 (medium)**:
`2026-10-28-02-status-subscribe-throttle-and-keep-confirmed.md`.
Unthrottled subscribe confirm emails, and re-subscribing un-confirmed a
subscriber. Fixed in #699.
- **X3 (medium on SaaS)**:
`2026-10-28-03-invite-lookup-without-org-scan.md`. Invite lookup scanned
every org. Fixed in #699.
- **X4 (low)**: `2026-10-28-04-snmp-community-secret-field.md`. The SNMP
community was not a secret field. Fixed in #699.
- **V1 (medium)**: `2026-10-27-01-device-consent-phishing-guard.md`.
Device-flow consent phishing. Fixed in #693.
- **W1 (low)**: `2026-10-27-02-disable-2fa-attempt-throttle.md`. `DELETE
/auth/2fa` had no attempt budget. Fixed in #693.
- **U1 (low)**:
`2026-10-26-02-ai-repair-hold-skips-param-only-secrets.md`. The `repair:
auto` hold applied only when the check's `secrets` map had a value.
Fixed in #683.
- **S1 (medium)**:
`2026-10-25-01-ai-repair-grant-dropped-by-reference-resolution.md`. The
repair grant was compared after `${…}` references were resolved. Fixed
in #678; U1 closed the remaining gap.
- **R1 (medium)**:
`2026-10-24-01-ai-repair-auto-apply-partial-runtime-host.md`. `repair:
auto` applied a candidate that kept a literal host and added one built
at runtime. Fixed in #663.
- **Q1 (medium)**:
`2026-10-23-02-ai-loop-secret-relay-through-model.md`. AI loops relayed
an encoded secret through the model.
- **P1 (medium)**:
`2026-10-22-01-ai-script-secret-host-guard-runtime.md`. AI runs with
real secrets were only host-checked by regex.
- **K1 (medium)**: `2026-10-20-01-sender-response-body-caps.md`.
Notification senders and RabbitMQ read responses uncapped.
- **J1 (medium)**: `2026-10-19-01-a2a-response-size-cap.md`. A2A
responses were read uncapped.
- **I1 (low)**: `2026-10-18-01-plugin-schema-file-ref.md`. Plugin schema
`$ref` could load local files.
- **G1/G2 (low)**: `2026-10-17-01-postgres-check-connection-config.md`.
Postgres conninfo escaping and fallback to the worker's `PG*` env.
- **F1**: `2026-10-16-15-pat-cache-revocation.md`. The PAT cache
outlived revocation.
- **E1**: `2026-10-16-14-totp-on-federated-sign-in.md`. No TOTP on
federated sign-in.
- **E2**: `2026-10-16-13-atomic-auth-attempt-counters.md`. Auth attempt
counters were not atomic.
- **H3**: `2026-10-16-12-mcp-tokens-rejected-on-rest.md`. MCP OAuth
tokens worked on REST.
- **H2**: `2026-10-16-11-slack-signature-fail-closed.md`. Slack
signature check failed open.
- **T1 / M2 (high)**: `2026-10-16-10-discovery-scans-egress-guard.md`.
Discovery scans were outside the egress policy.
- **N4**: `2026-10-16-09-js-check-nested-docker-guard.md`. A JS `docker`
sub-check bypassed the gate.
- **N3 (high)**: `2026-10-16-08-status-page-components-cross-org.md`.
Status-page components could be edited across orgs.
- **D2/D3 (high)**:
`2026-10-16-07-guard-status-subscriber-and-publication-webhooks.md`.
Subscriber and publication webhooks were not guarded.
- **C3**: `2026-10-16-06-accept-invite-existing-account.md`. Accepting
an invite logged in as an existing account.
- **C1**: `2026-10-16-05-kubeconfig-exec-and-incluster.md`. Kubeconfig
`exec` and `inCluster` were allowed.
- **N2**: `2026-10-16-04-mysql-dsn-injection.md`. MySQL DSN injection.
- **N1**: `2026-10-16-03-env-secret-reference-allowlist.md`. No
allowlist for `${env:}` references.
- **C2/H1**: `2026-10-16-02-token-purpose-separation.md`. Purpose tokens
were accepted as access tokens.
- **D1**: `2026-10-16-01-microsoft-signin-unverified-email-linking.md`.
Microsoft nOAuth email linking.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
fclairamb added a commit that referenced this pull request Oct 31, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.43.0](v0.42.1...v0.43.0)
(2026-10-31)


### Features

* auto-create a personal org for new users, resume OAuth after org
creation ([#716](#716))
([2ae5575](2ae5575))


### Bug Fixes

* **auth:** limit sign-ups per client IP (unconfirmed per day, once a
minute) ([#727](#727))
([b2eb48f](b2eb48f))
* **deps:** update github.com/dop251/goja digest to 032d024
([#724](#724))
([025e97a](025e97a))
* **deps:** update go dependencies (non-major)
([#725](#725))
([5796b1f](5796b1f))
* **deps:** update module github.com/prometheus/common to v0.73.1
([#720](#720))
([9bef875](9bef875))
* **deps:** update module github.com/slack-go/slack to v0.33.0
([#722](#722))
([ad19df4](ad19df4))
* **security:** bug-report budget for non-members, retention sparing
crawl reports
([#715](#715))
([d929999](d929999))
* **security:** JS check memory budget, re-authentication for new
sign-in factors
([#728](#728))
([a78f954](a78f954))


### Performance Improvements

* **dash0:** load only the active language's translations
([#729](#729))
([406f211](406f211))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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