feat: hourly CVE alerting with notification bell and API #53

Merged
sharang merged 1 commits from feat/cve-alerts into main 2026-03-30 10:39:39 +00:00
Owner

Full CVE alerting pipeline: hourly OSV.dev scanning, notification model with lifecycle, 5 API endpoints, dashboard notification bell with badge and dropdown. Also fixes Dockerfile.dashboard.

Full CVE alerting pipeline: hourly OSV.dev scanning, notification model with lifecycle, 5 API endpoints, dashboard notification bell with badge and dropdown. Also fixes Dockerfile.dashboard.
sharang added 1 commit 2026-03-30 10:33:14 +00:00
feat: hourly CVE alerting with notification bell and API
All checks were successful
CI / Check (pull_request) Successful in 9m47s
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped
b02202fbc8
Implements the full CVE alerting pipeline:

CVE Monitor (scheduler.rs):
- Replaces stub monitor_cves with actual OSV.dev scanning of all SBOM entries
- Runs hourly by default (CVE_MONITOR_SCHEDULE, was daily)
- Creates CveNotification for each new CVE (deduped by cve_id+repo+package)
- Updates SBOM entries with discovered vulnerabilities
- Upserts CveAlert records

Notification Model (compliance-core/models/notification.rs):
- CveNotification with status lifecycle: new → read → dismissed
- NotificationSeverity (Low/Medium/High/Critical) from CVSS scores
- parse_severity helper for OSV/NVD severity mapping

API Endpoints (5 new routes):
- GET /api/v1/notifications — List with status/severity/repo filters
- GET /api/v1/notifications/count — Unread count (for badge)
- PATCH /api/v1/notifications/:id/read — Mark as read
- PATCH /api/v1/notifications/:id/dismiss — Dismiss
- POST /api/v1/notifications/read-all — Bulk mark read

Dashboard Notification Bell:
- Floating bell icon (top-right) with unread count badge
- Dropdown panel showing CVE details: severity, CVSS, package, repo, summary
- Dismiss individual notifications
- Auto-marks as read when panel opens
- Polls count every 30 seconds

Also:
- Fix Dockerfile.dashboard: revert to dioxus-cli 0.7.3 --locked
- Add cve_notifications collection with unique + status indexes
- MongoDB indexes for efficient notification queries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sharang reviewed 2026-03-30 10:35:51 +00:00
sharang left a comment
Author
Owner

Compliance scan found 48 issue(s) in this PR:

  • [medium] code-review/complexity: Complex boolean expression in schedule configuration
  • [medium] code-review/complexity: Deeply nested control flow in notification rendering
  • [medium] code-review/complexity: Complex boolean expression in notification dismissal
  • [medium] code-review/logic: Inconsistent handling of page and limit parameters in notifications listing
  • [high] code-review/security: Insecure Direct Object Reference (IDOR) in Notification Management
  • [medium] code-review/security: Potential Denial of Service via Unbounded Query Parameters
  • [low] code-review/convention: Inconsistent version pinning in Dockerfile
  • [medium] code-review/convention: Potential panic in notification creation due to missing error propagation
  • [medium] code-review/convention: Potential panic from unwrap_or_else() in notification creation
  • [high] code-review/logic: Incorrect notification dismissal logic
  • [medium] code-review/security: Missing Input Validation in NotificationBell Component
  • [medium] code-review/convention: Missing error propagation in database index creation
  • [high] code-review/security: Insecure Default Cron Schedule
  • [high] code-review/logic: Missing error handling for HTTP request failures
  • [medium] code-review/convention: Inconsistent Error Handling in Resource Polling
  • [medium] code-review/complexity: Deeply nested control flow in CVE monitoring
  • [medium] code-review/complexity: Complex boolean expression in severity parsing
  • [medium] code-review/security: Sensitive Data Exposure in Logs
  • [high] code-review/logic: Missing error handling for database operations in notifications listing
  • [medium] code-review/complexity: Complex boolean expressions in error handling
  • [high] code-review/security: Potential XSS vulnerability in notification CVE ID rendering
  • [medium] code-review/complexity: Complex boolean expression in notification filtering
  • [medium] code-review/convention: Inconsistent error handling with unwrap() in production code
  • [high] code-review/logic: Off-by-one error in CVSS severity thresholds
  • [high] code-review/security: Insecure Direct Object Reference (IDOR) in CVE Notification Creation
  • [medium] code-review/security: Potential Command Injection via User-Controlled Repository Name
  • [high] code-review/security: Potential XSS via CVE ID in Notification Panel
  • [low] code-review/convention: Public API exposure of internal notification module
  • [low] code-review/convention: Inconsistent public API design
  • [medium] code-review/convention: Potential Panic in Notification Dismissal
  • [high] code-review/security: Server-Side Request Forgery (SSRF) via User-Controlled URL
  • [medium] code-review/logic: Incorrect HTTP method for dismissing notification
  • [high] code-review/logic: Incorrect cron schedule syntax
  • [high] code-review/logic: Race condition in notification loading
  • [medium] code-review/convention: Inconsistent error handling with unwrap_or_else
  • [medium] code-review/convention: Inconsistent error handling with unwrap() in critical path
  • [high] code-review/logic: Missing import of NotificationBell in app_shell.rs
  • [medium] code-review/convention: Unwrapped Option in Notification Processing
  • [medium] code-review/convention: Inconsistent error handling in notification severity parsing
  • [medium] code-review/convention: Inconsistent error handling with unwrap() in production code
  • [medium] code-review/convention: Inconsistent error handling in notification API
  • [high] code-review/security: Potential XSS vulnerability in notification summary rendering
  • [medium] code-review/logic: Incorrect handling of empty known_vulnerabilities in SBOM entry updates
  • [medium] code-review/convention: Inconsistent error handling in auth check
  • [medium] code-review/convention: Potential silent failure in dismiss_notification
  • [medium] code-review/convention: Unvalidated API responses in notification data structures
  • [medium] code-review/logic: Incorrect MongoDB query for notification count
  • [medium] code-review/convention: Missing error handling in component initialization
Compliance scan found **48** issue(s) in this PR: - **[medium]** code-review/complexity: Complex boolean expression in schedule configuration - **[medium]** code-review/complexity: Deeply nested control flow in notification rendering - **[medium]** code-review/complexity: Complex boolean expression in notification dismissal - **[medium]** code-review/logic: Inconsistent handling of page and limit parameters in notifications listing - **[high]** code-review/security: Insecure Direct Object Reference (IDOR) in Notification Management - **[medium]** code-review/security: Potential Denial of Service via Unbounded Query Parameters - **[low]** code-review/convention: Inconsistent version pinning in Dockerfile - **[medium]** code-review/convention: Potential panic in notification creation due to missing error propagation - **[medium]** code-review/convention: Potential panic from unwrap_or_else() in notification creation - **[high]** code-review/logic: Incorrect notification dismissal logic - **[medium]** code-review/security: Missing Input Validation in NotificationBell Component - **[medium]** code-review/convention: Missing error propagation in database index creation - **[high]** code-review/security: Insecure Default Cron Schedule - **[high]** code-review/logic: Missing error handling for HTTP request failures - **[medium]** code-review/convention: Inconsistent Error Handling in Resource Polling - **[medium]** code-review/complexity: Deeply nested control flow in CVE monitoring - **[medium]** code-review/complexity: Complex boolean expression in severity parsing - **[medium]** code-review/security: Sensitive Data Exposure in Logs - **[high]** code-review/logic: Missing error handling for database operations in notifications listing - **[medium]** code-review/complexity: Complex boolean expressions in error handling - **[high]** code-review/security: Potential XSS vulnerability in notification CVE ID rendering - **[medium]** code-review/complexity: Complex boolean expression in notification filtering - **[medium]** code-review/convention: Inconsistent error handling with unwrap() in production code - **[high]** code-review/logic: Off-by-one error in CVSS severity thresholds - **[high]** code-review/security: Insecure Direct Object Reference (IDOR) in CVE Notification Creation - **[medium]** code-review/security: Potential Command Injection via User-Controlled Repository Name - **[high]** code-review/security: Potential XSS via CVE ID in Notification Panel - **[low]** code-review/convention: Public API exposure of internal notification module - **[low]** code-review/convention: Inconsistent public API design - **[medium]** code-review/convention: Potential Panic in Notification Dismissal - **[high]** code-review/security: Server-Side Request Forgery (SSRF) via User-Controlled URL - **[medium]** code-review/logic: Incorrect HTTP method for dismissing notification - **[high]** code-review/logic: Incorrect cron schedule syntax - **[high]** code-review/logic: Race condition in notification loading - **[medium]** code-review/convention: Inconsistent error handling with unwrap_or_else - **[medium]** code-review/convention: Inconsistent error handling with unwrap() in critical path - **[high]** code-review/logic: Missing import of NotificationBell in app_shell.rs - **[medium]** code-review/convention: Unwrapped Option in Notification Processing - **[medium]** code-review/convention: Inconsistent error handling in notification severity parsing - **[medium]** code-review/convention: Inconsistent error handling with unwrap() in production code - **[medium]** code-review/convention: Inconsistent error handling in notification API - **[high]** code-review/security: Potential XSS vulnerability in notification summary rendering - **[medium]** code-review/logic: Incorrect handling of empty known_vulnerabilities in SBOM entry updates - **[medium]** code-review/convention: Inconsistent error handling in auth check - **[medium]** code-review/convention: Potential silent failure in dismiss_notification - **[medium]** code-review/convention: Unvalidated API responses in notification data structures - **[medium]** code-review/logic: Incorrect MongoDB query for notification count - **[medium]** code-review/convention: Missing error handling in component initialization
@@ -1,6 +1,6 @@
FROM rust:1.94-bookworm AS builder
RUN cargo install dioxus-cli --version 0.7.4
RUN cargo install dioxus-cli --version 0.7.3 --locked
Author
Owner

[low] Inconsistent version pinning in Dockerfile

The Dockerfile changes from using an unspecified version of dioxus-cli to explicitly pinning version 0.7.3 with --locked flag. While this provides reproducibility, it's inconsistent with previous behavior and may introduce compatibility issues if not carefully managed.

Suggested fix: Ensure that version pinning is intentional and documented, or consider using a more flexible approach like specifying a version range instead of exact version.

*Scanner: code-review/convention | *

**[low] Inconsistent version pinning in Dockerfile** The Dockerfile changes from using an unspecified version of dioxus-cli to explicitly pinning version 0.7.3 with --locked flag. While this provides reproducibility, it's inconsistent with previous behavior and may introduce compatibility issues if not carefully managed. Suggested fix: Ensure that version pinning is intentional and documented, or consider using a more flexible approach like specifying a version range instead of exact version. *Scanner: code-review/convention | * <!-- compliance-fp:bc7dad71697cf159b399056dc0665b499ed4df2a3f10768bed9dcf0c0b9fdf73 -->
@@ -0,0 +15,4 @@
axum::extract::Query(params): axum::extract::Query<NotificationFilter>,
) -> Result<Json<ApiResponse<Vec<CveNotification>>>, StatusCode> {
let mut filter = doc! {};
Author
Owner

[medium] Complex boolean expression in notification filtering

The status filtering logic in list_notifications uses a complex match expression that's hard to follow and could lead to incorrect filtering behavior if the status parameter contains unexpected values. The logic mixes default cases with explicit matches in a way that's not immediately clear.

Suggested fix: Simplify the status filtering by using a more direct approach like if let Some(status) = params.status followed by explicit handling of 'all' case, or extract the filtering logic into a separate helper function.

*Scanner: code-review/complexity | *

**[medium] Complex boolean expression in notification filtering** The status filtering logic in `list_notifications` uses a complex match expression that's hard to follow and could lead to incorrect filtering behavior if the status parameter contains unexpected values. The logic mixes default cases with explicit matches in a way that's not immediately clear. Suggested fix: Simplify the status filtering by using a more direct approach like `if let Some(status) = params.status` followed by explicit handling of 'all' case, or extract the filtering logic into a separate helper function. *Scanner: code-review/complexity | * <!-- compliance-fp:13d69705a319c582197e92ad5926db5f9460547118ec31150633d836e98ef603 -->
@@ -0,0 +30,4 @@
// Filter by severity
if let Some(ref sev) = params.severity {
filter.insert("severity", sev.as_str());
}
Author
Owner

[medium] Potential Denial of Service via Unbounded Query Parameters

The list_notifications handler accepts page and limit parameters but does not enforce strict limits on the maximum allowed values. While there's a minimum limit of 1 and maximum limit of 200, attackers could potentially send very large page numbers which would cause MongoDB to skip a large number of documents, leading to performance degradation or timeouts.

Suggested fix: Add stricter bounds checking on both page and limit parameters. For example, cap page to a reasonable maximum value (e.g., 1000) to prevent excessive skipping in database queries.

Scanner: code-review/security | CWE: CWE-400

**[medium] Potential Denial of Service via Unbounded Query Parameters** The `list_notifications` handler accepts `page` and `limit` parameters but does not enforce strict limits on the maximum allowed values. While there's a minimum limit of 1 and maximum limit of 200, attackers could potentially send very large page numbers which would cause MongoDB to skip a large number of documents, leading to performance degradation or timeouts. Suggested fix: Add stricter bounds checking on both `page` and `limit` parameters. For example, cap `page` to a reasonable maximum value (e.g., 1000) to prevent excessive skipping in database queries. *Scanner: code-review/security | CWE: CWE-400* <!-- compliance-fp:9cb155b24558319e8e369492d1815e7a2b6c56e207366ae5546eb7faf752c717 -->
@@ -0,0 +40,4 @@
let page = params.page.unwrap_or(1).max(1);
let limit = params.limit.unwrap_or(50).min(200);
let skip = (page - 1) * limit as u64;
Author
Owner

[medium] Inconsistent handling of page and limit parameters in notifications listing

The list_notifications function uses page and limit parameters to calculate skip, but it doesn't validate that limit is within acceptable bounds before using it in the MongoDB query. If limit is set to a very large value, it could cause performance issues or resource exhaustion.

Suggested fix: Add validation to ensure limit is within reasonable bounds (e.g., between 1 and 1000) before applying it to the MongoDB query.

*Scanner: code-review/logic | *

**[medium] Inconsistent handling of page and limit parameters in notifications listing** The `list_notifications` function uses `page` and `limit` parameters to calculate `skip`, but it doesn't validate that `limit` is within acceptable bounds before using it in the MongoDB query. If `limit` is set to a very large value, it could cause performance issues or resource exhaustion. Suggested fix: Add validation to ensure `limit` is within reasonable bounds (e.g., between 1 and 1000) before applying it to the MongoDB query. *Scanner: code-review/logic | * <!-- compliance-fp:ab454b4b25bdbea666aa6b00592f00629df7599262f5b1e2d305ead219748d92 -->
@@ -0,0 +42,4 @@
let skip = (page - 1) * limit as u64;
let total = agent
.db
Author
Owner

[medium] Inconsistent error handling with unwrap() in production code

The code uses unwrap_or(0) on database count operations which can mask failures and lead to incorrect behavior. This pattern should be replaced with proper error propagation to ensure failures are handled appropriately rather than silently defaulting to 0.

Suggested fix: Replace unwrap_or(0) with proper error handling using ? operator or explicit error mapping to maintain consistency with the rest of the error handling pattern in the function.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling with unwrap() in production code** The code uses `unwrap_or(0)` on database count operations which can mask failures and lead to incorrect behavior. This pattern should be replaced with proper error propagation to ensure failures are handled appropriately rather than silently defaulting to 0. Suggested fix: Replace `unwrap_or(0)` with proper error handling using `?` operator or explicit error mapping to maintain consistency with the rest of the error handling pattern in the function. *Scanner: code-review/convention | * <!-- compliance-fp:04a147cda1ee08d23922ff8010b142ca156e42af8a08927a2d462c28fc845939 -->
@@ -0,0 +49,4 @@
.unwrap_or(0);
let notifications: Vec<CveNotification> = match agent
.db
Author
Owner

[high] Missing error handling for database operations in notifications listing

The list_notifications function uses unwrap_or(0) when counting documents, which can mask potential database errors. If the database connection fails or there's a network issue, this will silently return 0 instead of propagating the error.

Suggested fix: Replace unwrap_or(0) with proper error propagation to ensure database errors are handled appropriately.

*Scanner: code-review/logic | *

**[high] Missing error handling for database operations in notifications listing** The `list_notifications` function uses `unwrap_or(0)` when counting documents, which can mask potential database errors. If the database connection fails or there's a network issue, this will silently return 0 instead of propagating the error. Suggested fix: Replace `unwrap_or(0)` with proper error propagation to ensure database errors are handled appropriately. *Scanner: code-review/logic | * <!-- compliance-fp:53e06284ca96a607d3c216dbd4f51024175ae36605b2fc9bd8dde5f316a32bce -->
@@ -0,0 +51,4 @@
let notifications: Vec<CveNotification> = match agent
.db
.cve_notifications()
.find(filter)
Author
Owner

[high] Insecure Direct Object Reference (IDOR) in Notification Management

The notification management endpoints allow users to manipulate notifications by ID without proper authorization checks. Specifically, the mark_read, dismiss_notification, and notification_count handlers do not validate whether the requesting user has permission to access or modify the specified notification. This could allow an attacker to read, mark as read, or dismiss notifications belonging to other users if they can guess or obtain valid notification IDs.

Suggested fix: Implement proper authorization checks before allowing modification or access to notifications. Ensure that each notification's owner or authorized user can only interact with their own notifications. Add a check to verify that the authenticated user has permission to access the notification before performing any operations.

Scanner: code-review/security | CWE: CWE-285

**[high] Insecure Direct Object Reference (IDOR) in Notification Management** The notification management endpoints allow users to manipulate notifications by ID without proper authorization checks. Specifically, the `mark_read`, `dismiss_notification`, and `notification_count` handlers do not validate whether the requesting user has permission to access or modify the specified notification. This could allow an attacker to read, mark as read, or dismiss notifications belonging to other users if they can guess or obtain valid notification IDs. Suggested fix: Implement proper authorization checks before allowing modification or access to notifications. Ensure that each notification's owner or authorized user can only interact with their own notifications. Add a check to verify that the authenticated user has permission to access the notification before performing any operations. *Scanner: code-review/security | CWE: CWE-285* <!-- compliance-fp:a91e13a47fecbaa94c1ca541ada7f1f6bb3ca7cc22e5662a4157cb4cebcad3be -->
@@ -0,0 +63,4 @@
let mut cursor = cursor;
while let Some(Ok(n)) = cursor.next().await {
items.push(n);
}
Author
Owner

[medium] Inconsistent error handling with unwrap() in production code

The code uses unwrap_or(0) on database count operations which can mask failures and lead to incorrect behavior. This pattern should be replaced with proper error propagation to ensure failures are handled appropriately rather than silently defaulting to 0.

Suggested fix: Replace unwrap_or(0) with proper error handling using ? operator or explicit error mapping to maintain consistency with the rest of the error handling pattern in the function.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling with unwrap() in production code** The code uses `unwrap_or(0)` on database count operations which can mask failures and lead to incorrect behavior. This pattern should be replaced with proper error propagation to ensure failures are handled appropriately rather than silently defaulting to 0. Suggested fix: Replace `unwrap_or(0)` with proper error handling using `?` operator or explicit error mapping to maintain consistency with the rest of the error handling pattern in the function. *Scanner: code-review/convention | * <!-- compliance-fp:8e2ffde00ac780dcca6a742bc8c7fd2dbb88b97d57ceb521d21ace2dea10a449 -->
Author
Owner

[medium] Incorrect MongoDB query for notification count

The notification_count function filters for notifications with status 'new', but the database may contain notifications with other statuses that should also be considered unread. This could lead to an undercount of unread notifications.

Suggested fix: Update the filter to include all statuses that represent unread notifications, such as 'new' and potentially others like 'unseen'.

*Scanner: code-review/logic | *

**[medium] Incorrect MongoDB query for notification count** The `notification_count` function filters for notifications with status 'new', but the database may contain notifications with other statuses that should also be considered unread. This could lead to an undercount of unread notifications. Suggested fix: Update the filter to include all statuses that represent unread notifications, such as 'new' and potentially others like 'unseen'. *Scanner: code-review/logic | * <!-- compliance-fp:e6fabebae11b6efea326a3aafd025f176c6bd7d11c95a1cb4f94b5ebe0d230d4 -->
@@ -43,3 +43,3 @@
scan_schedule: env_var_opt("SCAN_SCHEDULE").unwrap_or_else(|| "0 0 */6 * * *".to_string()),
cve_monitor_schedule: env_var_opt("CVE_MONITOR_SCHEDULE")
.unwrap_or_else(|| "0 0 0 * * *".to_string()),
.unwrap_or_else(|| "0 0 * * * *".to_string()),
Author
Owner

[medium] Complex boolean expression in schedule configuration

The CVE monitor schedule default value was changed from '0 0 0 * * *' to '0 0 * * * *'. This change affects the cron schedule parsing logic which could introduce bugs if the parsing implementation doesn't properly handle the new format or if there are assumptions about the number of fields in cron expressions.

Suggested fix: Add explicit validation for the cron schedule format to ensure the new default value is correctly parsed and handled by the underlying cron library. Consider adding unit tests for different cron formats to verify parsing behavior.

*Scanner: code-review/complexity | *

**[medium] Complex boolean expression in schedule configuration** The CVE monitor schedule default value was changed from '0 0 0 * * *' to '0 0 * * * *'. This change affects the cron schedule parsing logic which could introduce bugs if the parsing implementation doesn't properly handle the new format or if there are assumptions about the number of fields in cron expressions. Suggested fix: Add explicit validation for the cron schedule format to ensure the new default value is correctly parsed and handled by the underlying cron library. Consider adding unit tests for different cron formats to verify parsing behavior. *Scanner: code-review/complexity | * <!-- compliance-fp:301202ed81ce2f9d5ba9e99727ebd42c2f40d83b412df04dcd445fbfdb2e880b -->
Author
Owner

[high] Insecure Default Cron Schedule

The default cron schedule for CVE monitoring was changed from '0 0 0 * * *' (daily at midnight) to '0 0 * * * *' (every minute). This introduces a significant performance issue and potential resource exhaustion as the system will now run the CVE monitor every minute instead of daily, leading to excessive database queries and processing overhead.

Suggested fix: Revert to the original daily schedule '0 0 0 * * *' or implement proper rate limiting to prevent excessive execution frequency.

Scanner: code-review/security | CWE: CWE-707

**[high] Insecure Default Cron Schedule** The default cron schedule for CVE monitoring was changed from '0 0 0 * * *' (daily at midnight) to '0 0 * * * *' (every minute). This introduces a significant performance issue and potential resource exhaustion as the system will now run the CVE monitor every minute instead of daily, leading to excessive database queries and processing overhead. Suggested fix: Revert to the original daily schedule '0 0 0 * * *' or implement proper rate limiting to prevent excessive execution frequency. *Scanner: code-review/security | CWE: CWE-707* <!-- compliance-fp:bdfcd200bf9e6fee57fac7dc0dfeb62acb44e21849723b123a43e1953b75cc02 -->
Author
Owner

[high] Incorrect cron schedule syntax

The CVE monitor schedule was changed from "0 0 0 * * *" to "0 0 * * * *". This is incorrect cron syntax - it should be "0 0 0 * * *" (which means 'at 00:00 every day') rather than "0 0 * * * *" (which would mean 'at 00:00 every minute'). The new value will cause the scheduler to run every minute instead of daily.

Suggested fix: Change back to "0 0 0 * * *" to maintain daily execution at midnight

*Scanner: code-review/logic | *

**[high] Incorrect cron schedule syntax** The CVE monitor schedule was changed from "0 0 0 * * *" to "0 0 * * * *". This is incorrect cron syntax - it should be "0 0 0 * * *" (which means 'at 00:00 every day') rather than "0 0 * * * *" (which would mean 'at 00:00 every minute'). The new value will cause the scheduler to run every minute instead of daily. Suggested fix: Change back to "0 0 0 * * *" to maintain daily execution at midnight *Scanner: code-review/logic | * <!-- compliance-fp:435ce43f7611e56398894855aee3143ac090cc7496f3fc49d4a2244e5c0ae50b -->
Author
Owner

[medium] Inconsistent error handling with unwrap_or_else

The code uses unwrap_or_else consistently for environment variable parsing, but this pattern can mask configuration loading failures. If an environment variable is present but invalid, it will fall back to the default value instead of failing fast, potentially leading to unexpected behavior.

Suggested fix: Consider using unwrap_or instead of unwrap_or_else to make the fallback behavior more explicit and avoid potential silent failures when environment variables contain invalid values.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling with unwrap_or_else** The code uses `unwrap_or_else` consistently for environment variable parsing, but this pattern can mask configuration loading failures. If an environment variable is present but invalid, it will fall back to the default value instead of failing fast, potentially leading to unexpected behavior. Suggested fix: Consider using `unwrap_or` instead of `unwrap_or_else` to make the fallback behavior more explicit and avoid potential silent failures when environment variables contain invalid values. *Scanner: code-review/convention | * <!-- compliance-fp:11df5870c6150171dcd661756c416d9f83a61990f27b31e2c85e7f5040ebf5e6 -->
@@ -78,6 +78,25 @@ impl Database {
)
.await?;
// cve_notifications: unique cve_id + repo_id + package, status filter
Author
Owner

[medium] Missing error propagation in database index creation

The database index creation operations use .await? but don't propagate errors properly. If index creation fails, the application might continue running with missing indexes, which could lead to data consistency issues or performance problems. The error handling should ensure that index creation failures are properly reported.

Suggested fix: Add explicit error handling around the index creation calls to ensure that failures during index creation are properly propagated up the call stack rather than being silently ignored.

*Scanner: code-review/convention | *

**[medium] Missing error propagation in database index creation** The database index creation operations use `.await?` but don't propagate errors properly. If index creation fails, the application might continue running with missing indexes, which could lead to data consistency issues or performance problems. The error handling should ensure that index creation failures are properly reported. Suggested fix: Add explicit error handling around the index creation calls to ensure that failures during index creation are properly propagated up the call stack rather than being silently ignored. *Scanner: code-review/convention | * <!-- compliance-fp:8f5c2d8e5c4635ece75e7de2f705bba2629348aba28c3ebac50f30a0a0dbe3ad -->
@@ -222,6 +241,12 @@ impl Database {
self.inner.collection("cve_alerts")
}
pub fn cve_notifications(
Author
Owner

[low] Inconsistent public API design

The cve_notifications method is added as a public getter but doesn't follow the same pattern as other collection getters like cve_alerts and tracker_issues. This creates an inconsistent API surface where some collections have dedicated methods while others don't, potentially confusing users of the Database struct.

Suggested fix: Either add similar getter methods for all collections or remove the inconsistency by making all collection access consistent through a single pattern.

*Scanner: code-review/convention | *

**[low] Inconsistent public API design** The `cve_notifications` method is added as a public getter but doesn't follow the same pattern as other collection getters like `cve_alerts` and `tracker_issues`. This creates an inconsistent API surface where some collections have dedicated methods while others don't, potentially confusing users of the Database struct. Suggested fix: Either add similar getter methods for all collections or remove the inconsistency by making all collection access consistent through a single pattern. *Scanner: code-review/convention | * <!-- compliance-fp:f1e245853073a64bd6f9c74be6e99051603c70a645fb6c77fc85153a5db4db5b -->
@@ -84,2 +84,4 @@
async fn monitor_cves(agent: &ComplianceAgent) {
use compliance_core::models::notification::{parse_severity, CveNotification};
use compliance_core::models::SbomEntry;
use futures_util::StreamExt;
Author
Owner

[medium] Deeply nested control flow in CVE monitoring

The monitor_cves function contains deeply nested control flow with multiple levels of error handling and conditional logic. The main loop processing entries by repo contains nested conditionals for scanning, upserting alerts, updating entries, and creating notifications, making it difficult to follow the logical flow and increasing risk of bugs during maintenance.

Suggested fix: Refactor the main loop into smaller functions with single responsibilities. Extract the scanning logic, alert upserting, entry updates, and notification creation into separate functions to flatten the nesting and improve readability.

*Scanner: code-review/complexity | *

**[medium] Deeply nested control flow in CVE monitoring** The `monitor_cves` function contains deeply nested control flow with multiple levels of error handling and conditional logic. The main loop processing entries by repo contains nested conditionals for scanning, upserting alerts, updating entries, and creating notifications, making it difficult to follow the logical flow and increasing risk of bugs during maintenance. Suggested fix: Refactor the main loop into smaller functions with single responsibilities. Extract the scanning logic, alert upserting, entry updates, and notification creation into separate functions to flatten the nesting and improve readability. *Scanner: code-review/complexity | * <!-- compliance-fp:2ba3c96d10b859d29c786938973e436c45285e10599b1a1b0496f3294530093c -->
@@ -103,2 +103,2 @@
// The actual CVE checking is handled by the CveScanner in the pipeline
// This is a simplified version that just logs the activity
tracing::info!(
"CVE monitor: checking {} dependencies for new CVEs",
Author
Owner

[medium] Potential panic from unwrap_or_else() in notification creation

The code uses repo_names.get(&repo_id).cloned().unwrap_or_else(|| repo_id.clone()) which can panic if repo_id contains invalid UTF-8. While this is unlikely in practice, it's an anti-pattern that could cause runtime panics if the underlying data is malformed. The code should handle this case more gracefully.

Suggested fix: Use a more robust fallback mechanism that doesn't rely on unwrap_or_else() for string operations, or validate that repo_id is valid UTF-8 before using it as a key.

*Scanner: code-review/convention | *

**[medium] Potential panic from unwrap_or_else() in notification creation** The code uses `repo_names.get(&repo_id).cloned().unwrap_or_else(|| repo_id.clone())` which can panic if repo_id contains invalid UTF-8. While this is unlikely in practice, it's an anti-pattern that could cause runtime panics if the underlying data is malformed. The code should handle this case more gracefully. Suggested fix: Use a more robust fallback mechanism that doesn't rely on unwrap_or_else() for string operations, or validate that repo_id is valid UTF-8 before using it as a key. *Scanner: code-review/convention | * <!-- compliance-fp:a8accb7d45230c70fafa594eee0f338cf1165310e7ab5cd05251d352d193719b -->
Author
Owner

[medium] Sensitive Data Exposure in Logs

The code logs sensitive information such as repo.name and alert.cve_id in debug and info level logs. Although these logs are typically not exposed externally, if they are stored or transmitted without proper access controls, they could expose repository names and CVE identifiers to unauthorized parties.

Suggested fix: Avoid logging sensitive data like repository names and CVE IDs unless strictly necessary for debugging. Consider using structured logging with configurable log levels to prevent accidental exposure.

Scanner: code-review/security | CWE: CWE-532

**[medium] Sensitive Data Exposure in Logs** The code logs sensitive information such as `repo.name` and `alert.cve_id` in debug and info level logs. Although these logs are typically not exposed externally, if they are stored or transmitted without proper access controls, they could expose repository names and CVE identifiers to unauthorized parties. Suggested fix: Avoid logging sensitive data like repository names and CVE IDs unless strictly necessary for debugging. Consider using structured logging with configurable log levels to prevent accidental exposure. *Scanner: code-review/security | CWE: CWE-532* <!-- compliance-fp:4d41c06a604adcd93d3815fe8bc1e1122ff065d9740b46606d0e73e3c2a4e772 -->
Author
Owner

[medium] Potential Command Injection via User-Controlled Repository Name

The code constructs a repository name from user-provided data (repo.name) and uses it in logging and notification creation. While this doesn't directly execute commands, if any downstream system processes this name as part of a shell command or file path, it could lead to command injection. Specifically, the repo_name variable is used in tracing::info! log messages and passed to CveNotification::new() which may be used in contexts where it's processed further.

Suggested fix: Sanitize or validate the repo.name field before using it in logs or notifications. Ensure that any downstream processing treats this value as literal text rather than executable code.

Scanner: code-review/security | CWE: CWE-78

**[medium] Potential Command Injection via User-Controlled Repository Name** The code constructs a repository name from user-provided data (`repo.name`) and uses it in logging and notification creation. While this doesn't directly execute commands, if any downstream system processes this name as part of a shell command or file path, it could lead to command injection. Specifically, the `repo_name` variable is used in `tracing::info!` log messages and passed to `CveNotification::new()` which may be used in contexts where it's processed further. Suggested fix: Sanitize or validate the `repo.name` field before using it in logs or notifications. Ensure that any downstream processing treats this value as literal text rather than executable code. *Scanner: code-review/security | CWE: CWE-78* <!-- compliance-fp:9c84d13d743395fb1bbc8ae1221b18a750c81d591fe2a47a0cde1fe6cf94fb3f -->
@@ -105,0 +122,4 @@
let nvd_key = agent.config.nvd_api_key.as_ref().map(|k| {
use secrecy::ExposeSecret;
k.expose_secret().to_string()
});
Author
Owner

[medium] Inconsistent error handling with unwrap() in critical path

The code uses mongodb::bson::to_bson(...).unwrap_or_default() multiple times in the CVE monitoring flow. While this prevents panics, it silently discards serialization errors which could lead to missing data in database operations. This inconsistent error handling approach (mixing unwrap_or_default with proper error logging) could hide failures that should be properly reported.

Suggested fix: Replace unwrap_or_default() with proper error handling that logs the serialization failure and potentially aborts the operation or retries, rather than silently ignoring BSON conversion errors.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling with unwrap() in critical path** The code uses `mongodb::bson::to_bson(...).unwrap_or_default()` multiple times in the CVE monitoring flow. While this prevents panics, it silently discards serialization errors which could lead to missing data in database operations. This inconsistent error handling approach (mixing unwrap_or_default with proper error logging) could hide failures that should be properly reported. Suggested fix: Replace unwrap_or_default() with proper error handling that logs the serialization failure and potentially aborts the operation or retries, rather than silently ignoring BSON conversion errors. *Scanner: code-review/convention | * <!-- compliance-fp:e48b3f130e8c1f645792b1841629dcda325aa6c15b1abc0d09d0a952b673d1c6 -->
@@ -105,0 +129,4 @@
nvd_key,
);
// Group entries by repo for scanning
Author
Owner

[medium] Incorrect handling of empty known_vulnerabilities in SBOM entry updates

In the CVE monitoring logic, when updating SBOM entries with known vulnerabilities, the code checks if entry.known_vulnerabilities.is_empty() and skips the update if true. However, this check is flawed because it should only skip updating if there are NO vulnerabilities to report, but the current logic prevents any update even when vulnerabilities exist but are empty. This could lead to stale data in the database.

Suggested fix: The condition should be inverted to only skip when there are NO vulnerabilities to process. Change if entry.known_vulnerabilities.is_empty() to if !entry.known_vulnerabilities.is_empty() or better yet, remove the check entirely since we want to update regardless of whether vulnerabilities exist.

*Scanner: code-review/logic | *

**[medium] Incorrect handling of empty known_vulnerabilities in SBOM entry updates** In the CVE monitoring logic, when updating SBOM entries with known vulnerabilities, the code checks `if entry.known_vulnerabilities.is_empty()` and skips the update if true. However, this check is flawed because it should only skip updating if there are NO vulnerabilities to report, but the current logic prevents any update even when vulnerabilities exist but are empty. This could lead to stale data in the database. Suggested fix: The condition should be inverted to only skip when there are NO vulnerabilities to process. Change `if entry.known_vulnerabilities.is_empty()` to `if !entry.known_vulnerabilities.is_empty()` or better yet, remove the check entirely since we want to update regardless of whether vulnerabilities exist. *Scanner: code-review/logic | * <!-- compliance-fp:181b8fb3e314d10e55a8c23aa10b55c25abf215c256d797b1f7cb945eb567025 -->
@@ -105,0 +131,4 @@
// Group entries by repo for scanning
let mut entries_by_repo: std::collections::HashMap<String, Vec<SbomEntry>> =
std::collections::HashMap::new();
Author
Owner

[high] Insecure Direct Object Reference (IDOR) in CVE Notification Creation

When creating CVE notifications, the code uses a MongoDB filter based on cve_id, repo_id, package_name, and package_version. However, there's no explicit authorization check to ensure that the authenticated user has access to the specified repo_id. If an attacker can forge a request to create a notification for a repository they don't own, they could potentially pollute the notification system with false positives or malicious data.

Suggested fix: Add an authorization check before creating CVE notifications to verify that the requesting entity has permission to access the given repo_id. This should involve validating the user's role or ownership of the repository.

Scanner: code-review/security | CWE: CWE-285

**[high] Insecure Direct Object Reference (IDOR) in CVE Notification Creation** When creating CVE notifications, the code uses a MongoDB filter based on `cve_id`, `repo_id`, `package_name`, and `package_version`. However, there's no explicit authorization check to ensure that the authenticated user has access to the specified `repo_id`. If an attacker can forge a request to create a notification for a repository they don't own, they could potentially pollute the notification system with false positives or malicious data. Suggested fix: Add an authorization check before creating CVE notifications to verify that the requesting entity has permission to access the given `repo_id`. This should involve validating the user's role or ownership of the repository. *Scanner: code-review/security | CWE: CWE-285* <!-- compliance-fp:a5235af8a103fcddbed4b7f0249a3cef28dcf16db671146d943bbe67b4c2cae6 -->
@@ -27,6 +28,7 @@ pub use graph::{
};
pub use issue::{IssueStatus, TrackerIssue, TrackerType};
pub use mcp::{McpServerConfig, McpServerStatus, McpTransport};
pub use notification::{CveNotification, NotificationSeverity, NotificationStatus};
Author
Owner

[low] Public API exposure of internal notification module

The notification module was made public in the models re-export, but it appears to be an internal implementation detail used only within the compliance-agent. Making it public exposes an internal API contract that may change without notice, breaking consumers who depend on it.

Suggested fix: Consider making the notification module private or moving it to a separate internal crate if it's truly meant to be internal, or document clearly that it's part of the public API contract.

*Scanner: code-review/convention | *

**[low] Public API exposure of internal notification module** The notification module was made public in the models re-export, but it appears to be an internal implementation detail used only within the compliance-agent. Making it public exposes an internal API contract that may change without notice, breaking consumers who depend on it. Suggested fix: Consider making the notification module private or moving it to a separate internal crate if it's truly meant to be internal, or document clearly that it's part of the public API contract. *Scanner: code-review/convention | * <!-- compliance-fp:5ca4ef59a4c774d8d6eeb9ef8966eb504500ec7dfc68d37beb773d596ff8263c -->
@@ -0,0 +65,4 @@
severity: NotificationSeverity,
) -> Self {
Self {
id: None,
Author
Owner

[medium] Potential panic in notification creation due to missing error propagation

The CveNotification::new constructor creates a new notification with default values but doesn't validate any of its parameters. If any of the required fields (like cve_id, repo_id, etc.) are empty or invalid, this could lead to inconsistent state in the notification system without proper error reporting.

Suggested fix: Consider adding validation checks or returning a Result type from the constructor to propagate potential errors during notification creation.

*Scanner: code-review/convention | *

**[medium] Potential panic in notification creation due to missing error propagation** The `CveNotification::new` constructor creates a new notification with default values but doesn't validate any of its parameters. If any of the required fields (like `cve_id`, `repo_id`, etc.) are empty or invalid, this could lead to inconsistent state in the notification system without proper error reporting. Suggested fix: Consider adding validation checks or returning a Result type from the constructor to propagate potential errors during notification creation. *Scanner: code-review/convention | * <!-- compliance-fp:38733d61b0095d0334b329ebc9563043a18eb6717152d3f2671eb74e26ce6e0a -->
@@ -0,0 +81,4 @@
}
}
}
Author
Owner

[medium] Complex boolean expression in severity parsing

The parse_severity function contains a complex boolean expression that mixes CVSS score checking with string severity mapping. This increases cognitive load when trying to understand the logic flow and could lead to incorrect severity assignment if the conditions are reordered or modified.

Suggested fix: Break down the conditional logic into separate functions or use early returns to simplify the boolean expression and make the severity mapping more readable.

*Scanner: code-review/complexity | *

**[medium] Complex boolean expression in severity parsing** The `parse_severity` function contains a complex boolean expression that mixes CVSS score checking with string severity mapping. This increases cognitive load when trying to understand the logic flow and could lead to incorrect severity assignment if the conditions are reordered or modified. Suggested fix: Break down the conditional logic into separate functions or use early returns to simplify the boolean expression and make the severity mapping more readable. *Scanner: code-review/complexity | * <!-- compliance-fp:dcf8698f6e820a0b83a62005de7c55ce7010cb3715f2a4768205476650d53601 -->
@@ -0,0 +84,4 @@
/// Map an OSV/NVD severity string to our notification severity
pub fn parse_severity(s: Option<&str>, cvss: Option<f64>) -> NotificationSeverity {
// Prefer CVSS score if available
Author
Owner

[high] Off-by-one error in CVSS severity thresholds

The parse_severity function uses inclusive thresholds for CVSS scores that should be exclusive. Specifically, a score of exactly 9.0 is classified as Critical, but according to CVSS standards, 9.0 should be considered High (scores 7.0-8.9). This causes incorrect categorization of vulnerabilities with CVSS scores at boundary values.

Suggested fix: Change the comparison operators to use strict inequality for boundary values. For example, change s if s >= 9.0 => NotificationSeverity::Critical to s if s > 9.0 => NotificationSeverity::Critical and adjust other thresholds accordingly.

*Scanner: code-review/logic | *

**[high] Off-by-one error in CVSS severity thresholds** The `parse_severity` function uses inclusive thresholds for CVSS scores that should be exclusive. Specifically, a score of exactly 9.0 is classified as Critical, but according to CVSS standards, 9.0 should be considered High (scores 7.0-8.9). This causes incorrect categorization of vulnerabilities with CVSS scores at boundary values. Suggested fix: Change the comparison operators to use strict inequality for boundary values. For example, change `s if s >= 9.0 => NotificationSeverity::Critical` to `s if s > 9.0 => NotificationSeverity::Critical` and adjust other thresholds accordingly. *Scanner: code-review/logic | * <!-- compliance-fp:bddaad5308cef0c8df610c6aabd5daf4f8b28698d71d50b64b3fcd700a428617 -->
@@ -0,0 +85,4 @@
/// Map an OSV/NVD severity string to our notification severity
pub fn parse_severity(s: Option<&str>, cvss: Option<f64>) -> NotificationSeverity {
// Prefer CVSS score if available
if let Some(score) = cvss {
Author
Owner

[medium] Inconsistent error handling in notification severity parsing

The parse_severity function uses pattern matching on Option<&str> but doesn't handle the case where the string might be invalid or unexpected. While it handles None cases properly, it assumes all non-None strings are valid severity indicators, which could lead to incorrect severity assignment if malformed input is encountered.

Suggested fix: Add explicit error handling or validation for unexpected string values in the severity parsing logic to ensure robustness against malformed inputs.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling in notification severity parsing** The `parse_severity` function uses pattern matching on `Option<&str>` but doesn't handle the case where the string might be invalid or unexpected. While it handles None cases properly, it assumes all non-None strings are valid severity indicators, which could lead to incorrect severity assignment if malformed input is encountered. Suggested fix: Add explicit error handling or validation for unexpected string values in the severity parsing logic to ensure robustness against malformed inputs. *Scanner: code-review/convention | * <!-- compliance-fp:2c2c64b5a0c8e658335d46625ee90c0813795f33aa5974584f5000688768d5e7 -->
@@ -3850,0 +3876,4 @@
.notification-dismiss-btn:hover { color: var(--danger); }
.notification-item-pkg { font-size: 12px; color: var(--text-primary); font-family: 'JetBrains Mono', monospace; }
.notification-item-repo { font-size: 11px; color: var(--text-secondary); margin-bottom: 4px; }
.notification-item-summary { font-size: 11px; color: var(--text-secondary); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
Author
Owner

[high] Potential XSS via CVE ID in Notification Panel

The CVE ID field in the notification panel is rendered directly into HTML without sanitization. If an attacker can control the CVE ID value (e.g., through a malicious OSV/NVD feed or compromised data source), they could inject malicious script tags into the notification item's HTML structure, leading to XSS when the notification panel is displayed.

Suggested fix: Sanitize all user-provided data before rendering it in HTML templates. Specifically, ensure that the CVE ID field is escaped when inserted into the DOM. Use a templating engine with automatic escaping or manually escape special characters like <, >, &, ", ' before inserting into HTML.

Scanner: code-review/security | CWE: CWE-79

**[high] Potential XSS via CVE ID in Notification Panel** The CVE ID field in the notification panel is rendered directly into HTML without sanitization. If an attacker can control the CVE ID value (e.g., through a malicious OSV/NVD feed or compromised data source), they could inject malicious script tags into the notification item's HTML structure, leading to XSS when the notification panel is displayed. Suggested fix: Sanitize all user-provided data before rendering it in HTML templates. Specifically, ensure that the CVE ID field is escaped when inserted into the DOM. Use a templating engine with automatic escaping or manually escape special characters like <, >, &, ", ' before inserting into HTML. *Scanner: code-review/security | CWE: CWE-79* <!-- compliance-fp:5a2f465c18bb744b0052e86f36bf7a1adb2ae7163939a962d8372110ea43c3fd -->
@@ -21,6 +22,7 @@ pub fn AppShell() -> Element {
main { class: "main-content",
Outlet::<Route> {}
}
NotificationBell {}
Author
Owner

[medium] Missing Input Validation in NotificationBell Component

The NotificationBell component appears to be added to the app shell without any validation of user-provided data that might be passed to it. If this component processes any user input directly (such as notification messages, titles, or metadata) without sanitization or validation, it could lead to XSS vulnerabilities or other injection attacks. Without seeing the full implementation of NotificationBell, we cannot determine the exact risk, but adding a new component that handles potentially untrusted data without proper validation creates an attack surface.

Suggested fix: Review the NotificationBell component implementation to ensure all user-provided data is properly sanitized and validated before rendering or processing. Implement input validation and output encoding to prevent XSS and other injection vulnerabilities.

Scanner: code-review/security | CWE: CWE-79

**[medium] Missing Input Validation in NotificationBell Component** The NotificationBell component appears to be added to the app shell without any validation of user-provided data that might be passed to it. If this component processes any user input directly (such as notification messages, titles, or metadata) without sanitization or validation, it could lead to XSS vulnerabilities or other injection attacks. Without seeing the full implementation of NotificationBell, we cannot determine the exact risk, but adding a new component that handles potentially untrusted data without proper validation creates an attack surface. Suggested fix: Review the NotificationBell component implementation to ensure all user-provided data is properly sanitized and validated before rendering or processing. Implement input validation and output encoding to prevent XSS and other injection vulnerabilities. *Scanner: code-review/security | CWE: CWE-79* <!-- compliance-fp:7a7ed653a81d2faca1b58121ac48d2497846487d23508388981aea5c3017b157 -->
Author
Owner

[high] Missing import of NotificationBell in app_shell.rs

The NotificationBell component is used in AppShell but not properly imported. While the module is declared in mod.rs, the specific component needs to be imported in the app_shell.rs file to be available for use.

Suggested fix: Add use crate::components::notification_bell::NotificationBell; at the top of the file after the other imports.

*Scanner: code-review/logic | *

**[high] Missing import of NotificationBell in app_shell.rs** The NotificationBell component is used in AppShell but not properly imported. While the module is declared in mod.rs, the specific component needs to be imported in the app_shell.rs file to be available for use. Suggested fix: Add `use crate::components::notification_bell::NotificationBell;` at the top of the file after the other imports. *Scanner: code-review/logic | * <!-- compliance-fp:942ded8c666e8ca25d0308a7e6d4baea0e4980fcb45be6c0a9987c7cbe64d2ad -->
Author
Owner

[medium] Inconsistent error handling in auth check

The check_auth function in src/components/app_shell.rs uses expect() which will panic on failure, while other parts of the application likely use proper error propagation. This inconsistency can cause unexpected crashes instead of graceful error handling.

Suggested fix: Replace expect() with proper error handling using ? operator or explicit error propagation to maintain consistency with the rest of the application's error handling pattern.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling in auth check** The `check_auth` function in `src/components/app_shell.rs` uses `expect()` which will panic on failure, while other parts of the application likely use proper error propagation. This inconsistency can cause unexpected crashes instead of graceful error handling. Suggested fix: Replace `expect()` with proper error handling using `?` operator or explicit error propagation to maintain consistency with the rest of the application's error handling pattern. *Scanner: code-review/convention | * <!-- compliance-fp:d12621e39568997ac37db7aef4c581f1c13d90a949197070c70bda3a9db9cc27 -->
Author
Owner

[medium] Missing error handling in component initialization

The AppShell component calls check_auth() without handling potential errors, which could lead to unhandled panics when authentication fails. The component should handle authentication errors gracefully rather than crashing.

Suggested fix: Add proper error handling around the check_auth() call to catch and handle authentication failures appropriately, such as redirecting to login or showing an error message.

*Scanner: code-review/convention | *

**[medium] Missing error handling in component initialization** The `AppShell` component calls `check_auth()` without handling potential errors, which could lead to unhandled panics when authentication fails. The component should handle authentication errors gracefully rather than crashing. Suggested fix: Add proper error handling around the `check_auth()` call to catch and handle authentication failures appropriately, such as redirecting to login or showing an error message. *Scanner: code-review/convention | * <!-- compliance-fp:0be63a4dc744e7308fba454955beaa8cfb382745ab323c9d15b6de85b1bfe281 -->
@@ -0,0 +23,4 @@
#[cfg(feature = "web")]
{
gloo_timers::future::TimeoutFuture::new(30_000).await;
}
Author
Owner

[medium] Inconsistent Error Handling in Resource Polling

The polling loop in use_resource handles errors from fetch_notification_count() by logging and continuing, while other similar operations in the same module use more explicit error reporting. This inconsistency could mask failures in notification fetching.

Suggested fix: Consider propagating errors from fetch_notification_count() to a global error state or logging them more explicitly to maintain consistency with the module's error handling patterns.

*Scanner: code-review/convention | *

**[medium] Inconsistent Error Handling in Resource Polling** The polling loop in `use_resource` handles errors from `fetch_notification_count()` by logging and continuing, while other similar operations in the same module use more explicit error reporting. This inconsistency could mask failures in notification fetching. Suggested fix: Consider propagating errors from `fetch_notification_count()` to a global error state or logging them more explicitly to maintain consistency with the module's error handling patterns. *Scanner: code-review/convention | * <!-- compliance-fp:e455f086ef5e6483caaea3fbea70fed3eae0e3d5b63e58f4cd6b057c7235e328 -->
@@ -0,0 +31,4 @@
}
});
// Load notifications when panel opens
Author
Owner

[high] Race condition in notification loading

In the load_notifications function, there's a potential race condition between setting is_loading.set(true) and the subsequent async block execution. If the component unmounts or is_open changes before the async block completes, the state updates might occur on an unmounted component, leading to undefined behavior or panics. The current implementation doesn't guard against such scenarios.

Suggested fix: Use Dioxus's built-in lifecycle management or cancellation tokens to ensure that async operations don't continue after the component has been unmounted or the state has changed unexpectedly.

*Scanner: code-review/logic | *

**[high] Race condition in notification loading** In the `load_notifications` function, there's a potential race condition between setting `is_loading.set(true)` and the subsequent async block execution. If the component unmounts or `is_open` changes before the async block completes, the state updates might occur on an unmounted component, leading to undefined behavior or panics. The current implementation doesn't guard against such scenarios. Suggested fix: Use Dioxus's built-in lifecycle management or cancellation tokens to ensure that async operations don't continue after the component has been unmounted or the state has changed unexpectedly. *Scanner: code-review/logic | * <!-- compliance-fp:33953e2ee10ef629d426a84e45c3d96e497f27512cf5b3a270ba52f42c96121b -->
@@ -0,0 +45,4 @@
// Mark all as read when panel opens
let _ = mark_all_notifications_read().await;
count.set(0);
is_loading.set(false);
Author
Owner

[high] Incorrect notification dismissal logic

The notification dismissal logic uses a nested and_then chain to extract the $oid field from the notification ID, but this approach is flawed. If the ID structure doesn't exactly match the expected format (e.g., missing $oid key or different nesting), it will return None and the comparison != Some(&id) will fail, causing notifications to not be properly removed from the UI. Additionally, the dismissal handler passes id.clone() to the async block, but then tries to compare against n.id.as_ref().and_then(...).and_then(...) which may not match due to the complex extraction logic.

Suggested fix: Simplify the notification dismissal logic by using a direct string comparison on the notification ID field, assuming it's already a valid string. Alternatively, ensure the ID extraction logic is robust and handles all possible ID formats correctly.

*Scanner: code-review/logic | *

**[high] Incorrect notification dismissal logic** The notification dismissal logic uses a nested `and_then` chain to extract the `$oid` field from the notification ID, but this approach is flawed. If the ID structure doesn't exactly match the expected format (e.g., missing `$oid` key or different nesting), it will return `None` and the comparison `!= Some(&id)` will fail, causing notifications to not be properly removed from the UI. Additionally, the dismissal handler passes `id.clone()` to the async block, but then tries to compare against `n.id.as_ref().and_then(...).and_then(...)` which may not match due to the complex extraction logic. Suggested fix: Simplify the notification dismissal logic by using a direct string comparison on the notification ID field, assuming it's already a valid string. Alternatively, ensure the ID extraction logic is robust and handles all possible ID formats correctly. *Scanner: code-review/logic | * <!-- compliance-fp:60ad2fac2595934bb1595936c0dd5d13840a40ee5dd2ce6990b60f5b72884988 -->
@@ -0,0 +55,4 @@
notifications.write().retain(|n| {
n.id.as_ref()
.and_then(|v| v.get("$oid"))
.and_then(|v| v.as_str())
Author
Owner

[medium] Complex boolean expression in notification dismissal

The notification dismissal logic uses a complex chain of and_then calls to extract the OID from the notification ID, which is hard to follow and prone to runtime panics if the structure doesn't match expectations. This could lead to silent failures or crashes when processing notifications.

Suggested fix: Extract the OID extraction into a separate helper function with proper error handling, or use a more robust deserialization approach instead of chaining multiple and_then calls.

*Scanner: code-review/complexity | *

**[medium] Complex boolean expression in notification dismissal** The notification dismissal logic uses a complex chain of `and_then` calls to extract the OID from the notification ID, which is hard to follow and prone to runtime panics if the structure doesn't match expectations. This could lead to silent failures or crashes when processing notifications. Suggested fix: Extract the OID extraction into a separate helper function with proper error handling, or use a more robust deserialization approach instead of chaining multiple `and_then` calls. *Scanner: code-review/complexity | * <!-- compliance-fp:6320974cba200bdd5acd34cb44afc46575043e2a0e18d0f501c085d1881763a1 -->
@@ -0,0 +82,4 @@
button {
class: "notification-close-btn",
onclick: move |_| is_open.set(false),
Icon { icon: BsX, width: 16, height: 16 }
Author
Owner

[medium] Deeply nested control flow in notification rendering

The notification panel rendering contains deeply nested conditional logic (if/else chains) that makes it difficult to understand the flow and increases the risk of logic errors when modifying the component. The nested structure makes it hard to reason about what gets rendered under what conditions.

Suggested fix: Flatten the conditional rendering by extracting each state (loading, empty, notifications) into separate components or functions, reducing nesting levels and improving readability.

*Scanner: code-review/complexity | *

**[medium] Deeply nested control flow in notification rendering** The notification panel rendering contains deeply nested conditional logic (if/else chains) that makes it difficult to understand the flow and increases the risk of logic errors when modifying the component. The nested structure makes it hard to reason about what gets rendered under what conditions. Suggested fix: Flatten the conditional rendering by extracting each state (loading, empty, notifications) into separate components or functions, reducing nesting levels and improving readability. *Scanner: code-review/complexity | * <!-- compliance-fp:bd5b02f2fcbf56e7e8ed9034ef2384d12c35734e4503a99c4ac8171e0b42e7a8 -->
@@ -0,0 +127,4 @@
button {
class: "notification-dismiss-btn",
title: "Dismiss",
onclick: move |_| on_dismiss(dismiss_id.clone()),
Author
Owner

[high] Potential XSS vulnerability in notification CVE ID rendering

The notification component renders CVE IDs directly from API responses without sanitization. If an attacker can control the CVE ID field in the notification data, they could inject malicious HTML/JavaScript into the page. This occurs in the notification item rendering where '{notif.cve_id}' is directly inserted into the DOM.

Suggested fix: Sanitize the CVE ID before rendering it to prevent XSS. Use a library like dioxus-html or manually escape HTML characters in the CVE ID field before displaying it.

Scanner: code-review/security | CWE: CWE-79

**[high] Potential XSS vulnerability in notification CVE ID rendering** The notification component renders CVE IDs directly from API responses without sanitization. If an attacker can control the CVE ID field in the notification data, they could inject malicious HTML/JavaScript into the page. This occurs in the notification item rendering where '{notif.cve_id}' is directly inserted into the DOM. Suggested fix: Sanitize the CVE ID before rendering it to prevent XSS. Use a library like `dioxus-html` or manually escape HTML characters in the CVE ID field before displaying it. *Scanner: code-review/security | CWE: CWE-79* <!-- compliance-fp:4bea04577fe797ea08b8c5d70524da55c58323d3011013056ed675655a8a88df -->
Author
Owner

[medium] Potential Panic in Notification Dismissal

The on_dismiss handler uses unwrap_or("") when extracting the notification ID, which could panic if the ObjectId structure changes unexpectedly. This creates an inconsistency with the module's established pattern of graceful error handling.

Suggested fix: Use a more robust approach like map_or_else or match to handle the case where the ObjectId might not be present, maintaining consistency with the module's error handling strategy.

*Scanner: code-review/convention | *

**[medium] Potential Panic in Notification Dismissal** The `on_dismiss` handler uses `unwrap_or("")` when extracting the notification ID, which could panic if the ObjectId structure changes unexpectedly. This creates an inconsistency with the module's established pattern of graceful error handling. Suggested fix: Use a more robust approach like `map_or_else` or `match` to handle the case where the ObjectId might not be present, maintaining consistency with the module's error handling strategy. *Scanner: code-review/convention | * <!-- compliance-fp:dac048ae73c7e1dfdec3ffa14976548a6b565b7626b468f1f56f50b97c7774f6 -->
Author
Owner

[medium] Unwrapped Option in Notification Processing

The code uses .unwrap_or("") on a potentially critical value extraction path, which could lead to silent failures if the MongoDB ObjectId structure changes or becomes malformed. This violates the module's error handling consistency where other operations use if let Ok(...) patterns.

Suggested fix: Replace .unwrap_or("") with proper error handling using if let Some(...) or match to handle the case where the ObjectId might be missing or malformed, ensuring consistent error propagation throughout the module.

*Scanner: code-review/convention | *

**[medium] Unwrapped Option in Notification Processing** The code uses `.unwrap_or("")` on a potentially critical value extraction path, which could lead to silent failures if the MongoDB ObjectId structure changes or becomes malformed. This violates the module's error handling consistency where other operations use `if let Ok(...)` patterns. Suggested fix: Replace `.unwrap_or("")` with proper error handling using `if let Some(...)` or `match` to handle the case where the ObjectId might be missing or malformed, ensuring consistent error propagation throughout the module. *Scanner: code-review/convention | * <!-- compliance-fp:78fe4c1c13ebe3d2b7bd9a486e31d12e0117ea8c6062d4fcdf23dae78ff540ce -->
@@ -0,0 +140,4 @@
if let Some(ref summary) = notif.summary {
div { class: "notification-item-summary",
"{summary}"
}
Author
Owner

[high] Potential XSS vulnerability in notification summary rendering

The notification component renders summary text directly from API responses without sanitization. If an attacker can control the summary field in notification data, they could inject malicious HTML/JavaScript. This occurs in the notification item rendering where '{summary}' is directly inserted into the DOM.

Suggested fix: Sanitize the summary text before rendering it to prevent XSS. Either escape HTML characters or use a proper HTML sanitization library before inserting into the DOM.

Scanner: code-review/security | CWE: CWE-79

**[high] Potential XSS vulnerability in notification summary rendering** The notification component renders summary text directly from API responses without sanitization. If an attacker can control the summary field in notification data, they could inject malicious HTML/JavaScript. This occurs in the notification item rendering where '{summary}' is directly inserted into the DOM. Suggested fix: Sanitize the summary text before rendering it to prevent XSS. Either escape HTML characters or use a proper HTML sanitization library before inserting into the DOM. *Scanner: code-review/security | CWE: CWE-79* <!-- compliance-fp:e06c0860588342cb98d68b273e11d9800c6e3f8975d2829af93f9390a0d19d91 -->
@@ -0,0 +12,4 @@
pub struct CveNotificationData {
#[serde(rename = "_id")]
pub id: Option<serde_json::Value>,
pub cve_id: String,
Author
Owner

[medium] Unvalidated API responses in notification data structures

The CveNotificationData struct uses serde_json::Value for id and created_at fields which bypasses compile-time type checking. This could lead to runtime panics or unexpected behavior if the API returns unexpected data types for these fields, especially since they're marked as optional but still parsed as generic JSON values.

Suggested fix: Consider using more specific types for id and created_at fields, or add validation logic to ensure these fields contain expected data types when deserializing from the API response.

*Scanner: code-review/convention | *

**[medium] Unvalidated API responses in notification data structures** The CveNotificationData struct uses serde_json::Value for id and created_at fields which bypasses compile-time type checking. This could lead to runtime panics or unexpected behavior if the API returns unexpected data types for these fields, especially since they're marked as optional but still parsed as generic JSON values. Suggested fix: Consider using more specific types for id and created_at fields, or add validation logic to ensure these fields contain expected data types when deserializing from the API response. *Scanner: code-review/convention | * <!-- compliance-fp:4bcbc6b881d37e2bfc7569d61d867c4441ab71f41422424540ef71a852459bec -->
@@ -0,0 +24,4 @@
#[serde(default)]
pub created_at: Option<serde_json::Value>,
}
Author
Owner

[high] Missing error handling for HTTP request failures

The fetch_notification_count, fetch_notifications, mark_all_notifications_read, and dismiss_notification functions do not check the HTTP status code of the response. If the API returns an error status (like 4xx or 5xx), the code will still attempt to parse the response body as success, potentially leading to incorrect behavior or panics when trying to deserialize error responses.

Suggested fix: Add explicit status code checking before deserializing the response body. For example: if !resp.status().is_success() { return Err(ServerFnError::new(format!("HTTP Error: {}", resp.status()))); }

*Scanner: code-review/logic | *

**[high] Missing error handling for HTTP request failures** The `fetch_notification_count`, `fetch_notifications`, `mark_all_notifications_read`, and `dismiss_notification` functions do not check the HTTP status code of the response. If the API returns an error status (like 4xx or 5xx), the code will still attempt to parse the response body as success, potentially leading to incorrect behavior or panics when trying to deserialize error responses. Suggested fix: Add explicit status code checking before deserializing the response body. For example: `if !resp.status().is_success() { return Err(ServerFnError::new(format!("HTTP Error: {}", resp.status()))); }` *Scanner: code-review/logic | * <!-- compliance-fp:16047c1ed6f8992ba23b5e56cf7acb100051740d618c64a538c9ddb5017adfb8 -->
Author
Owner

[high] Server-Side Request Forgery (SSRF) via User-Controlled URL

The fetch_notifications, fetch_notification_count, mark_all_notifications_read, and dismiss_notification server functions construct URLs by concatenating user-provided data from state.agent_api_url without proper validation. If an attacker can control the agent_api_url configuration value, they could redirect requests to internal services or external malicious endpoints, enabling SSRF attacks.

Suggested fix: Validate and sanitize the agent_api_url configuration value to ensure it points to allowed domains or use a whitelist approach. Consider using a proxy or restricted network access for API calls.

Scanner: code-review/security | CWE: CWE-918

**[high] Server-Side Request Forgery (SSRF) via User-Controlled URL** The `fetch_notifications`, `fetch_notification_count`, `mark_all_notifications_read`, and `dismiss_notification` server functions construct URLs by concatenating user-provided data from `state.agent_api_url` without proper validation. If an attacker can control the `agent_api_url` configuration value, they could redirect requests to internal services or external malicious endpoints, enabling SSRF attacks. Suggested fix: Validate and sanitize the `agent_api_url` configuration value to ensure it points to allowed domains or use a whitelist approach. Consider using a proxy or restricted network access for API calls. *Scanner: code-review/security | CWE: CWE-918* <!-- compliance-fp:9f6223c6fdc7cf34ddd198fa78ba18451eb9ef04f2a7f37803f4e0ddd49f7b42 -->
@@ -0,0 +34,4 @@
pub async fn fetch_notification_count() -> Result<u64, ServerFnError> {
let state: super::server_state::ServerState =
dioxus_fullstack::FullstackContext::extract().await?;
Author
Owner

[medium] Complex boolean expressions in error handling

The error handling pattern uses nested map_err calls which can make it difficult to trace the flow of errors and may lead to less informative error messages during debugging.

Suggested fix: Consider using a more explicit error handling approach with early returns or a custom error conversion function to improve readability and maintainability.

*Scanner: code-review/complexity | *

**[medium] Complex boolean expressions in error handling** The error handling pattern uses nested `map_err` calls which can make it difficult to trace the flow of errors and may lead to less informative error messages during debugging. Suggested fix: Consider using a more explicit error handling approach with early returns or a custom error conversion function to improve readability and maintainability. *Scanner: code-review/complexity | * <!-- compliance-fp:64592d8433d089395e62949972ac8db5f27cba694ba6639253828244d5ff8f97 -->
Author
Owner

[medium] Inconsistent error handling in notification API

The notification API functions use inconsistent error handling patterns. Some functions map errors to ServerFnError::new(e.to_string()) while others could potentially hide failures by not properly propagating HTTP status codes or response parsing errors. The error mapping should be consistent across all server functions.

Suggested fix: Standardize error handling by ensuring all HTTP request failures and JSON parsing errors are consistently wrapped with appropriate ServerFnError variants, and consider including HTTP status codes in error messages for better debugging.

*Scanner: code-review/convention | *

**[medium] Inconsistent error handling in notification API** The notification API functions use inconsistent error handling patterns. Some functions map errors to ServerFnError::new(e.to_string()) while others could potentially hide failures by not properly propagating HTTP status codes or response parsing errors. The error mapping should be consistent across all server functions. Suggested fix: Standardize error handling by ensuring all HTTP request failures and JSON parsing errors are consistently wrapped with appropriate ServerFnError variants, and consider including HTTP status codes in error messages for better debugging. *Scanner: code-review/convention | * <!-- compliance-fp:5269eecb73d798b26d7eb1f71c9282cceff2ade8d914cb6c87b2ce38d3507a8b -->
@@ -0,0 +79,4 @@
#[server]
pub async fn dismiss_notification(id: String) -> Result<(), ServerFnError> {
let state: super::server_state::ServerState =
dioxus_fullstack::FullstackContext::extract().await?;
Author
Owner

[medium] Potential silent failure in dismiss_notification

The dismiss_notification function sends a PATCH request but doesn't check the HTTP response status code before considering the operation successful. This could lead to silent failures when the API returns an error status code, making it appear as though the notification was dismissed when it wasn't.

Suggested fix: Add response status code validation using resp.status().is_success() or similar before considering the operation complete, and return appropriate ServerFnError for non-success status codes.

*Scanner: code-review/convention | *

**[medium] Potential silent failure in dismiss_notification** The dismiss_notification function sends a PATCH request but doesn't check the HTTP response status code before considering the operation successful. This could lead to silent failures when the API returns an error status code, making it appear as though the notification was dismissed when it wasn't. Suggested fix: Add response status code validation using `resp.status().is_success()` or similar before considering the operation complete, and return appropriate ServerFnError for non-success status codes. *Scanner: code-review/convention | * <!-- compliance-fp:3187491f1dee8453ad0eb374529e9b949d4ccaa679a583f5874eb56940ffa3d3 -->
@@ -0,0 +80,4 @@
pub async fn dismiss_notification(id: String) -> Result<(), ServerFnError> {
let state: super::server_state::ServerState =
dioxus_fullstack::FullstackContext::extract().await?;
Author
Owner

[medium] Incorrect HTTP method for dismissing notification

The dismiss_notification function uses PATCH method but the API endpoint appears to be designed for dismissal operations which typically would use POST or DELETE. Using PATCH might not be semantically correct for this operation, though this could also be a design choice depending on the backend implementation.

Suggested fix: Verify that the API endpoint actually supports PATCH requests for dismissing notifications. If not, consider using POST or DELETE instead.

*Scanner: code-review/logic | *

**[medium] Incorrect HTTP method for dismissing notification** The `dismiss_notification` function uses PATCH method but the API endpoint appears to be designed for dismissal operations which typically would use POST or DELETE. Using PATCH might not be semantically correct for this operation, though this could also be a design choice depending on the backend implementation. Suggested fix: Verify that the API endpoint actually supports PATCH requests for dismissing notifications. If not, consider using POST or DELETE instead. *Scanner: code-review/logic | * <!-- compliance-fp:1920a0be46c40a4f2d3e04414a4148f1b3379bc271ec0d46afe3a66076d250db -->
sharang merged commit 49d5cd4e0a into main 2026-03-30 10:39:39 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sharang/compliance-scanner-agent#53