Skip to content

notifications: preliminary UI work#306

Draft
illegalprime wants to merge 1 commit into
eden/notifications.grafanafrom
eden/notifications.ui
Draft

notifications: preliminary UI work#306
illegalprime wants to merge 1 commit into
eden/notifications.grafanafrom
eden/notifications.ui

Conversation

@illegalprime
Copy link
Copy Markdown
Contributor

UI work expose notifications controls and alerting sinks.

@github-actions github-actions Bot added javascript Pull requests that update javascript code client server shared labels May 22, 2026
@github-actions
Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (8ff083d7e8b99a2addbc3a88dd7fd9b781de5381...7811814206a760a070cab4ed89b23fd2073f64bf, exact PR three-dot diff)
  • Model: gpt-5.5

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: HIGH

Findings

[HIGH] Notifications endpoints are session-only and miss admin authorization

  • Category: Auth
  • Location: server/internal/handlers/notifications/handler.go:67
  • Description: Every notifications route is wrapped only with h.authed(...). The hand-rolled auth path validates the session cookie, but it does not look up or populate the caller role and never calls the existing admin gate used by settings-style management APIs.
  • Impact: Any authenticated non-admin user can create/delete notification channels, send test deliveries, pause/resume alert rules, and create/delete silences for their org.
  • Recommendation: Use the generated Connect handlers with the standard auth interceptor and add an explicit admin/permission gate, or extend this temporary handler to load role via UserManagementStore and require ADMIN/SUPER_ADMIN for all mutating notification operations.

[HIGH] Webhook and SMTP destinations allow server-side request forgery

  • Category: Network Discovery
  • Location: server/internal/domain/notifications/service.go:665
  • Description: User-controlled webhook URLs and SMTP hosts are passed directly into Grafana contact point settings and can be exercised immediately through TestChannel, with no scheme, host, DNS, or private-network validation.
  • Impact: An authenticated user can cause the Grafana sidecar to connect to internal Docker services, loopback-only endpoints, link-local metadata services, or other network targets reachable from Grafana/fleet-api.
  • Recommendation: Validate webhook URLs and SMTP hosts server-side. Restrict schemes, reject loopback/link-local/RFC1918/internal Docker names unless explicitly allowlisted, resolve DNS before use, and enforce egress controls around Grafana.

[HIGH] Empty or malformed silence scopes can mute an entire organization

  • Category: Reliability
  • Location: server/internal/domain/notifications/service.go:905
  • Description: domainSilenceToGrafana always adds the organization_id matcher, but it only adds the rule/group/site/device matcher if the corresponding ID field is non-empty. The UI exposes group/site/device scope choices while only sending a rule picker payload, so those choices can produce a silence with only organization_id.
  • Impact: A user can create a broad org-wide silence that suppresses all matching alerts during the window, hiding outages, overheating, pool failures, or command failures.
  • Recommendation: Validate scope-specific required fields before writing to Grafana, reject empty target scopes, verify target ownership/existence, and hide group/site/device scopes until selectors are implemented. Escape device IDs when building regex matchers.

[HIGH] Grafana error logging can leak webhook and SMTP secrets

  • Category: gRPC
  • Location: server/internal/domain/notifications/grafana_client.go:263
  • Description: On any non-2xx Grafana response, the client logs the full JSON request body. Channel create/update/test bodies include authorization_credentials and smtpPassword.
  • Impact: A Grafana validation error or transient failure can write webhook bearer tokens and SMTP passwords to fleet-api logs, where they may be retained, shipped, or read by operators without secret access.
  • Recommendation: Redact sensitive fields before logging. Prefer logging method/path/status and a sanitized request summary; never log contact point secret values.

[MEDIUM] Channel updates cannot preserve existing webhook secrets

  • Category: Reliability
  • Location: server/internal/domain/notifications/service.go:162
  • Description: When an update does not include a fresh secret, the service preserves only the HasSecret flag. It then encodes webhook settings with authorization_credentials set from the empty readback value, so the old bearer token is not actually preserved.
  • Impact: Renaming or editing a webhook channel can silently clear or overwrite its authorization credential while the UI still reports that a secret exists, causing later alerts/tests to fail unexpectedly.
  • Recommendation: Do not send secret fields on update unless a new secret is supplied, or store/retrieve the secret server-side. Make the returned has_secret reflect the real persisted Grafana state.

[MEDIUM] Notifications bypass generated Connect/protobuf validation and use a divergent JSON contract

  • Category: Protobuf
  • Location: server/cmd/fleetd/main.go:550
  • Description: The PR adds generated notificationsv1connect code, but fleetd registers a custom JSON HTTP handler instead. That bypasses the repo’s Connect interceptor chain and buf.validate interceptor, and the custom TypeScript client uses lowercase string enums instead of the generated protobuf JSON enum contract.
  • Impact: Generated clients will not reliably interoperate with the server, and proto validation rules such as max lengths/min lengths are not enforced on this API surface.
  • Recommendation: Implement the generated Connect service handlers against the domain service and register them with the standard interceptor chain. Remove the hand-written wire DTOs once the generated client is used.

Notes

No cryptostealing or pool hijacking behavior was visible in the reviewed diff. No Rust ASIC plugin or miner command execution changes were included in this review scope.


Generated by Codex Security Review |
Triggered by: @illegalprime |
Review workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client javascript Pull requests that update javascript code server shared

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant