Best and simplest tool for website change detection, web page monitoring, and website change alerts. Perfect for tracking content changes, price drops, restock alerts, and website defacement monitoring—all for free or enjoy our SaaS plan!
This report summarizes scanner evidence for dgtlmoon/changedetection.io, a Python project with 34,880 GitHub stars. SynthScan examined 111,983 lines of code across 518 source files, recording 2709 pattern matches distributed across 22 syntactic categories. The legacy adjusted pattern signal is 37.3 (High pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 1605 finding(s).
Are imports declared and package/API names verified? 453 finding(s).
Are wrappers, guards, and repeated structures necessary? 1850 finding(s).
Which changes need focused human review? 2709 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 2709 distinct pattern matches across 22 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | changedetectionio/pluggy_interface.py | 280 | def inject_datastore_into_plugins(datastore): | CODE |
| LOW⚡ | changedetectionio/pluggy_interface.py | 296 | def register_builtin_fetchers(): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 64 | def get_itemprop_availability_override(self, content, fetcher_name, fetcher_instance, url, llm_intent=None): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 244 | def load_plugins_from_directories(): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 318 | def register_builtin_restock_plugins(): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 336 | def collect_ui_edit_stats_extras(watch): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 351 | def collect_fetcher_status_icons(fetcher_name): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 371 | def get_itemprop_availability_from_plugin(content, fetcher_name, fetcher_instance, url, llm_intent=None): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 563 | def get_plugin_template_paths(): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 619 | def apply_update_handler_alter(update_handler, watch, datastore): | CODE |
| LOW⚡ | changedetectionio/worker.py | 790 | async def send_content_changed_notification(watch_uuid, notification_q, datastore): | CODE |
| LOW⚡ | changedetectionio/worker.py | 803 | async def send_filter_failure_notification(watch_uuid, notification_q, datastore): | CODE |
| LOW⚡ | changedetectionio/worker.py | 816 | async def send_step_failure_notification(watch_uuid, step_n, notification_q, datastore): | CODE |
| LOW | changedetectionio/worker.py | 32 | def set_watch_minitext_status(watch, status): | CODE |
| LOW | changedetectionio/rss_tools.py | 9 | def cdata_in_document_to_text(html_content: str, render_anchor_tag_content=False) -> str: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 134 | async def start_single_async_worker(worker_id, update_q, notification_q, app, datastore, executor=None): | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 351 | def is_watch_running_by_another_worker(watch_uuid, current_worker_id): | CODE |
| LOW | changedetectionio/worker_pool.py | 285 | def claim_uuid_for_processing(uuid, worker_id): | CODE |
| LOW | changedetectionio/worker_pool.py | 312 | def release_uuid_from_processing(uuid, worker_id): | CODE |
| LOW | changedetectionio/worker_pool.py | 447 | def adjust_async_worker_count(new_count, update_q=None, notification_q=None, app=None, datastore=None): | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 551 | def _emit_notification_signal(self, item: Dict[str, Any]): | CODE |
| LOW | changedetectionio/notification_service.py | 57 | def watch_will_send_content_changed_notification(datastore, watch): | CODE |
| LOW | changedetectionio/notification_service.py | 261 | def set_random_for_validation(self): | CODE |
| LOW | changedetectionio/notification_service.py | 279 | def add_rendered_diff_to_notification_vars(notification_scan_text:str, prev_snapshot:str, current_snapshot:str, word_dif | CODE |
| LOW | changedetectionio/notification_service.py | 344 | def set_basic_notification_vars(current_snapshot, prev_snapshot, watch, triggered_text, timestamp_changed=None): | CODE |
| LOW | changedetectionio/notification_service.py | 376 | def queue_notification_for_watch(self, n_object: NotificationContextData, watch, date_index_from=-2, date_index_to=- | CODE |
| LOW | changedetectionio/notification_service.py | 433 | def send_content_changed_notification(self, watch_uuid): | CODE |
| LOW | changedetectionio/notification_service.py | 477 | def send_filter_failure_notification(self, watch_uuid): | CODE |
| LOW | changedetectionio/notification_service.py | 525 | def send_step_failure_notification(self, watch_uuid, step_n): | STRING |
| LOW | changedetectionio/notification_service.py | 574 | def create_notification_service(datastore, notification_q): | STRING |
| LOW⚡ | changedetectionio/validate_url.py | 203 | def is_url_private_or_parser_confused(url): | CODE |
| LOW | changedetectionio/__init__.py | 81 | def configure_litellm_pricing_source(): | CODE |
| LOW | changedetectionio/__init__.py | 534 | def queue_watches_for_recheck(datastore, iteration): | CODE |
| LOW | changedetectionio/forms.py | 883 | # def validate_notification_urls(self, field): | COMMENT |
| LOW | changedetectionio/forms.py | 260 | def validate_time_between_check_has_values(form): | CODE |
| LOW | changedetectionio/html_tools.py | 227 | def perl_style_slash_enclosed_regex_to_options(regex): | CODE |
| LOW | changedetectionio/html_tools.py | 277 | def subtractive_xpath_selector(selectors: List[str], html_content: str) -> str: | CODE |
| LOW | changedetectionio/html_tools.py | 535 | def _sanitize_lone_surrogate_str(value: str) -> str: | CODE |
| LOW | changedetectionio/html_tools.py | 538 | def _sanitize_lone_surrogates(value): | CODE |
| LOW | changedetectionio/html_tools.py | 592 | def _get_stripped_text_from_json_match(match): | CODE |
| LOW | changedetectionio/html_tools.py | 613 | def extract_json_blob_from_html(content, ensure_is_ldjson_info_type, json_filter): | CODE |
| LOW | changedetectionio/html_tools.py | 790 | def cdata_in_document_to_text(html_content: str, render_anchor_tag_content=False) -> str: | CODE |
| LOW | changedetectionio/html_tools.py | 882 | def workarounds_for_obfuscations(content): | CODE |
| LOW | changedetectionio/auth_decorator.py | 16 | def login_optionally_required(func): | CODE |
| LOW | changedetectionio/languages.py | 74 | def _build_short_timeago_rows(): | CODE |
| LOW | changedetectionio/languages.py | 98 | def register_short_timeago_locale(flask_locale): | CODE |
| LOW | changedetectionio/flask_app.py | 195 | def _configure_plugin_templates(): | CODE |
| LOW | changedetectionio/flask_app.py | 505 | def _get_watch_queue_position(watch_obj): | CODE |
| LOW | changedetectionio/flask_app.py | 512 | def _get_current_worker_count(): | CODE |
| LOW | changedetectionio/flask_app.py | 837 | def inject_llm_features_disabled(): | CODE |
| LOW | changedetectionio/flask_app.py | 843 | def inject_has_visual_browser(): | CODE |
| LOW | changedetectionio/flask_app.py | 916 | def strip_duplicate_date_header(response): | CODE |
| LOW | changedetectionio/flask_app.py | 1094 | def before_request_handle_cookie_x_settings(): | CODE |
| LOW | changedetectionio/flask_app.py | 1666 | def ticker_thread_check_time_launch_checks(): | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 122 | def build_preview_system_prompt() -> str: | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 139 | def build_change_summary_prompt( | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 164 | def build_change_summary_system_prompt() -> str: | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 206 | def build_setup_system_prompt() -> str: | CODE |
| LOW⚡ | changedetectionio/llm/evaluator.py | 438 | def get_global_token_budget_month(datastore=None) -> int: | CODE |
| LOW | changedetectionio/llm/evaluator.py | 174 | def apply_local_token_multiplier(base_max_tokens: int, llm_cfg: dict) -> int: | CODE |
| 1117 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | changedetectionio/__init__.py | 24 | # ============================================================================== | COMMENT |
| MEDIUM | changedetectionio/__init__.py | 26 | # ============================================================================== | COMMENT |
| MEDIUM | changedetectionio/__init__.py | 61 | # ============================================================================== | COMMENT |
| MEDIUM | changedetectionio/html_tools.py | 11 | # --------------------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/html_tools.py | 91 | # --------------------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/test_cli_opts.sh | 55 | # ============================================================================= | COMMENT |
| MEDIUM | changedetectionio/test_cli_opts.sh | 57 | # ============================================================================= | COMMENT |
| MEDIUM | changedetectionio/test_cli_opts.sh | 198 | # ============================================================================= | COMMENT |
| MEDIUM | changedetectionio/test_cli_opts.sh | 200 | # ============================================================================= | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 429 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 431 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 629 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 631 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 828 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 830 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 885 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 887 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 267 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 269 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 370 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 372 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 538 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 540 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 727 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 730 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 739 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 742 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 752 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 756 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 773 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 776 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 863 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 865 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 872 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 874 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 886 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 888 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 892 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 894 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 904 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 906 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 690 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 692 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 709 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 712 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 919 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 922 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 125 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 127 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 234 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 236 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 334 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 336 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 425 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 427 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 458 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 460 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 538 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 540 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 589 | # --------------------------------------------------------------------------- | COMMENT |
| 151 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | changedetectionio/pluggy_interface.py | 271 | print(f"Error loading plugin {module_name}: {e}") | CODE |
| LOW | changedetectionio/pluggy_interface.py | 332 | except Exception as e: | CODE |
| LOW | changedetectionio/pluggy_interface.py | 534 | except Exception as e: | CODE |
| LOW | changedetectionio/pluggy_interface.py | 558 | except Exception as e: | CODE |
| LOW | changedetectionio/pluggy_interface.py | 675 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker.py | 799 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker.py | 812 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker.py | 825 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 121 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 136 | except Exception as health_e: | CODE |
| LOW | changedetectionio/worker.py | 405 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 532 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 588 | except Exception as _fe: | CODE |
| LOW | changedetectionio/worker.py | 605 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 623 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 636 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 662 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 685 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 708 | except Exception as cleanup_error: | CODE |
| LOW | changedetectionio/worker.py | 721 | except Exception as finalize_error: | CODE |
| LOW | changedetectionio/worker.py | 733 | except Exception as release_error: | CODE |
| LOW | changedetectionio/is_safe_url.py | 110 | except Exception as e: | CODE |
| LOW | changedetectionio/rss_tools.py | 201 | except Exception as e: | STRING |
| LOW⚡ | changedetectionio/worker_pool.py | 129 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 368 | except Exception as uuid_e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 392 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 400 | except Exception as health_e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 406 | except Exception: | CODE |
| LOW | changedetectionio/worker_pool.py | 81 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 162 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 208 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 266 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 278 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 437 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 258 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 267 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 277 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 548 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 560 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 60 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 76 | except Exception: | CODE |
| LOW | changedetectionio/queue_handlers.py | 89 | except Exception as notif_e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 101 | except Exception as signal_e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 107 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 131 | except Exception as signal_e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 141 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 167 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 210 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 220 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 233 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 307 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 343 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 384 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 395 | except Exception: | CODE |
| LOW | changedetectionio/queue_handlers.py | 412 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 420 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 446 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 468 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 491 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 506 | except Exception as e: | CODE |
| 293 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH⚡ | docs/api-spec.yaml | 1412 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH⚡ | docs/api-spec.yaml | 1416 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH⚡ | docs/api-spec.yaml | 1420 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH⚡ | docs/api-spec.yaml | 1425 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2124 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2130 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2136 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2144 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 29 | For example: `x-api-key: YOUR_API_KEY` | CODE |
| HIGH | docs/api-spec.yaml | 162 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 196 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 215 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 239 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 255 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 953 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 958 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1026 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1041 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1099 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1104 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1161 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1173 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1219 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1224 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1257 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1262 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1298 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1303 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1333 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1338 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1616 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1622 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1656 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1661 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1695 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1705 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1745 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1750 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1797 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1808 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1848 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1853 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1880 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1885 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1905 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1918 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1959 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1971 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 2007 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 2019 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 2052 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 2057 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 2233 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 2238 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH⚡ | docs/api_v1/index.html | 1075 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH⚡ | docs/api_v1/index.html | 1079 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH⚡ | docs/api_v1/index.html | 1083 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH | docs/api_v1/index.html | 474 | <p>For example: <code>x-api-key: YOUR_API_KEY</code></p> | CODE |
| HIGH | docs/api_v1/index.html | 476 | <p>For example: <code>x-api-key: YOUR_API_KEY</code></p> | CODE |
| HIGH | docs/api_v1/index.html | 498 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| 30 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | changedetectionio/worker_pool.py | 270 | except ValueError: | CODE |
| HIGH | changedetectionio/worker_pool.py | 106 | except RuntimeError: | CODE |
| HIGH | changedetectionio/queue_handlers.py | 395 | except Exception: | CODE |
| HIGH | changedetectionio/queue_handlers.py | 76 | except Exception: | CODE |
| HIGH | changedetectionio/favicon_utils.py | 31 | except Exception: | CODE |
| HIGH | changedetectionio/gc_cleanup.py | 82 | except (AttributeError, TypeError): | CODE |
| HIGH | changedetectionio/gc_cleanup.py | 107 | except (AttributeError, TypeError): | CODE |
| HIGH | changedetectionio/gc_cleanup.py | 89 | except (AttributeError, TypeError): | CODE |
| HIGH | changedetectionio/validate_url.py | 190 | except Exception: | CODE |
| HIGH | changedetectionio/validate_url.py | 198 | except Exception: | CODE |
| HIGH | changedetectionio/__init__.py | 77 | except Exception: | CODE |
| HIGH | changedetectionio/flask_app.py | 1578 | except: | CODE |
| HIGH | changedetectionio/flask_app.py | 1584 | except: | CODE |
| HIGH | changedetectionio/llm/client.py | 197 | except Exception: | CODE |
| HIGH | changedetectionio/llm/evaluator.py | 449 | except (ValueError, TypeError): | CODE |
| HIGH | changedetectionio/llm/evaluator.py | 456 | except (ValueError, TypeError): | CODE |
| HIGH | changedetectionio/browser_steps/browser_steps.py | 561 | except: | CODE |
| HIGH | changedetectionio/browser_steps/browser_steps.py | 555 | except: | CODE |
| HIGH | …ctionio/notification/apprise_plugin/custom_handlers.py | 152 | except Exception: | CODE |
| HIGH | changedetectionio/tests/conftest.py | 220 | except (ValueError, RuntimeError): | CODE |
| HIGH | changedetectionio/tests/conftest.py | 452 | except Exception: | CODE |
| HIGH | changedetectionio/tests/conftest.py | 460 | except Exception: | CODE |
| HIGH | changedetectionio/tests/util.py | 436 | except (AttributeError, PermissionError): | CODE |
| HIGH | changedetectionio/tests/test_xpath_selector.py | 627 | except elementpath.ElementPathError: | CODE |
| HIGH | changedetectionio/tests/test_xpath_selector.py | 635 | except elementpath.ElementPathError: | CODE |
| HIGH | changedetectionio/realtime/socket_server.py | 271 | except Exception: | CODE |
| HIGH | changedetectionio/processors/__init__.py | 79 | except Exception as e: | CODE |
| HIGH | changedetectionio/processors/base.py | 148 | except OSError: | CODE |
| HIGH | changedetectionio/processors/base.py | 141 | except OSError: | CODE |
| HIGH | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 168 | except: | CODE |
| HIGH | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 324 | except: | CODE |
| HIGH | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 455 | except: | CODE |
| HIGH | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 599 | except: | CODE |
| HIGH | …sors/image_ssim_diff/image_handler/isolated_libvips.py | 113 | except: | CODE |
| HIGH | …sors/image_ssim_diff/image_handler/isolated_libvips.py | 198 | except: | CODE |
| HIGH | …sors/image_ssim_diff/image_handler/isolated_libvips.py | 321 | except: | CODE |
| HIGH | …angedetectionio/processors/text_json_diff/processor.py | 336 | except Exception: | CODE |
| HIGH | …ionio/processors/restock_diff/pure_python_extractor.py | 271 | except ValueError: | CODE |
| HIGH | …ionio/processors/restock_diff/pure_python_extractor.py | 142 | except ValueError: | CODE |
| HIGH | …ionio/processors/restock_diff/pure_python_extractor.py | 246 | except ValueError: | CODE |
| HIGH | changedetectionio/processors/restock_diff/processor.py | 195 | except (NameError, UnboundLocalError): | CODE |
| HIGH | changedetectionio/processors/restock_diff/processor.py | 199 | except (NameError, UnboundLocalError): | CODE |
| HIGH | changedetectionio/conditions/__init__.py | 80 | except (ValueError, TypeError): | CODE |
| HIGH | changedetectionio/conditions/__init__.py | 177 | except Exception as e: | CODE |
| HIGH | changedetectionio/model/Tags.py | 26 | except FileNotFoundError: | CODE |
| HIGH | changedetectionio/model/__init__.py | 513 | except AttributeError: | CODE |
| HIGH | changedetectionio/model/__init__.py | 540 | except AttributeError: | CODE |
| HIGH | changedetectionio/model/Watch.py | 130 | except Exception: | CODE |
| HIGH | changedetectionio/blueprint/ui/queue.py | 167 | except Exception: | CODE |
| HIGH | changedetectionio/blueprint/ui/diff.py | 40 | except Exception: | CODE |
| HIGH | changedetectionio/blueprint/settings/llm.py | 28 | except Exception: | CODE |
| HIGH | changedetectionio/blueprint/settings/llm.py | 45 | except Exception: | CODE |
| HIGH | changedetectionio/blueprint/imports/importer.py | 139 | except KeyError: | CODE |
| HIGH | changedetectionio/blueprint/imports/importer.py | 141 | except IndexError: | CODE |
| HIGH | changedetectionio/blueprint/imports/importer.py | 149 | except KeyError: | CODE |
| HIGH | changedetectionio/blueprint/imports/importer.py | 151 | except IndexError: | CODE |
| HIGH | changedetectionio/blueprint/watchlist/__init__.py | 181 | except Exception: | CODE |
| HIGH | changedetectionio/store/updates.py | 115 | except: | CODE |
| HIGH | changedetectionio/store/file_saving_datastore.py | 126 | except (OSError, AttributeError): | CODE |
| HIGH | changedetectionio/store/file_saving_datastore.py | 146 | except: | CODE |
| 3 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/worker.py | 330 | CODE | |
| LOW | changedetectionio/worker.py | 406 | CODE | |
| LOW | changedetectionio/worker.py | 459 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 3 | CODE | |
| LOW | changedetectionio/gc_cleanup.py | 9 | CODE | |
| LOW | changedetectionio/validate_url.py | 3 | CODE | |
| LOW | changedetectionio/forms.py | 22 | CODE | |
| LOW | changedetectionio/forms.py | 550 | CODE | |
| LOW | changedetectionio/auth_decorator.py | 3 | CODE | |
| LOW | changedetectionio/auth_decorator.py | 4 | CODE | |
| LOW | changedetectionio/time_handler.py | 2 | CODE | |
| LOW | changedetectionio/languages.py | 5 | CODE | |
| LOW | changedetectionio/llm/evaluator.py | 40 | CODE | |
| LOW | …angedetectionio/content_fetchers/screenshot_handler.py | 9 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 4 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 11 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 30 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 192 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 185 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 188 | CODE | |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 9 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 3 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 12 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 40 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 40 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 40 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 4 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 33 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 34 | CODE | |
| LOW | changedetectionio/notification/handler.py | 311 | CODE | |
| LOW | changedetectionio/notification/handler.py | 313 | CODE | |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 61 | CODE | |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 61 | CODE | |
| LOW | …ctionio/notification/apprise_plugin/custom_handlers.py | 53 | CODE | |
| LOW | …ctionio/notification/apprise_plugin/custom_handlers.py | 63 | CODE | |
| LOW | changedetectionio/tests/test_rss_reader_mode.py | 3 | CODE | |
| LOW | changedetectionio/tests/test_rss_reader_mode.py | 7 | CODE | |
| LOW | changedetectionio/tests/test_rss_reader_mode.py | 7 | CODE | |
| LOW | changedetectionio/tests/test_rss_reader_mode.py | 7 | CODE | |
| LOW | changedetectionio/tests/test_rss_reader_mode.py | 7 | CODE | |
| LOW | changedetectionio/tests/test_rss_reader_mode.py | 7 | CODE | |
| LOW | changedetectionio/tests/test_queue_handler.py | 4 | CODE | |
| LOW | changedetectionio/tests/test_queue_handler.py | 4 | CODE | |
| LOW | changedetectionio/tests/test_queue_handler.py | 5 | CODE | |
| LOW | changedetectionio/tests/test_preview_endpoints.py | 3 | CODE | |
| LOW | changedetectionio/tests/test_preview_endpoints.py | 5 | CODE | |
| LOW | changedetectionio/tests/test_preview_endpoints.py | 5 | CODE | |
| LOW | changedetectionio/tests/test_preview_endpoints.py | 5 | CODE | |
| LOW | changedetectionio/tests/test_backend.py | 6 | CODE | |
| LOW | changedetectionio/tests/test_backend.py | 6 | CODE | |
| LOW | changedetectionio/tests/test_lxml_concurrency.py | 17 | CODE | |
| LOW | changedetectionio/tests/test_api_openapi.py | 9 | CODE | |
| LOW | changedetectionio/tests/test_api_openapi.py | 12 | CODE | |
| LOW | changedetectionio/tests/test_api_openapi.py | 12 | CODE | |
| LOW | changedetectionio/tests/test_access_control.py | 1 | CODE | |
| LOW | changedetectionio/tests/test_access_control.py | 5 | CODE | |
| LOW | changedetectionio/tests/test_ignore_regex_text.py | 3 | CODE | |
| LOW | changedetectionio/tests/test_security.py | 3 | CODE | |
| LOW | changedetectionio/tests/test_security.py | 11 | CODE | |
| LOW | changedetectionio/tests/test_security.py | 388 | CODE | |
| 247 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | .github/workflows/test-stack-reusable-workflow.yml | 464 | # Create a watch via API through nginx proxy subpath | COMMENT |
| MEDIUM | .github/workflows/test-stack-reusable-workflow.yml | 800 | # Create a watch with tag "github-group-test" via API | COMMENT |
| MEDIUM | .github/workflows/test-stack-reusable-workflow.yml | 814 | # Create a specific test URL watch | COMMENT |
| MEDIUM | changedetectionio/is_safe_url.py | 93 | # Create a URL adapter bound to the server name | COMMENT |
| MEDIUM | changedetectionio/worker_pool.py | 55 | # Create a new event loop for this thread | COMMENT |
| MEDIUM | changedetectionio/gc_cleanup.py | 53 | # Create a new thread local object to encourage cleanup of old ones | COMMENT |
| MEDIUM | changedetectionio/__init__.py | 327 | # Create the datadir if it doesnt exist | COMMENT |
| MEDIUM | changedetectionio/test_cli_opts.sh | 148 | # Create a watch using CLI, then recheck it | COMMENT |
| MEDIUM | changedetectionio/flask_app.py | 205 | # Create a ChoiceLoader that searches app templates first, then plugin templates | COMMENT |
| MEDIUM | changedetectionio/notification/handler.py | 108 | # Define the mapping between your placeholders and markdown markers | COMMENT |
| MEDIUM | changedetectionio/notification/handler.py | 132 | # Define the mapping between your placeholders and markdown markers | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 958 | # Create a real watch and trigger a check so we have a valid backup structure | COMMENT |
| MEDIUM | changedetectionio/tests/test_rss_group.py | 47 | # Create a tag/group | STRING |
| MEDIUM | changedetectionio/tests/test_rss_group.py | 160 | # Create a tag with no watches | STRING |
| MEDIUM | changedetectionio/tests/test_rss_group.py | 197 | # Create a tag | STRING |
| MEDIUM | changedetectionio/tests/test_tag_colour.py | 83 | # Creating a tag with a bad colour in one shot must fail too | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_api_security.py | 50 | # Create a valid watch first | STRING |
| MEDIUM | changedetectionio/tests/test_api_security.py | 333 | # Create a watch | STRING |
| MEDIUM | changedetectionio/tests/test_basic_socketio.py | 24 | # Create a test client for SocketIO | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_commit_persistence.py | 28 | # Create a watch | COMMENT |
| MEDIUM | changedetectionio/tests/test_commit_persistence.py | 519 | # Create a tag | COMMENT |
| MEDIUM | …ctionio/tests/test_api_notification_urls_validation.py | 128 | # Create a tag | COMMENT |
| MEDIUM | changedetectionio/tests/test_backup.py | 138 | # Create a full backup | COMMENT |
| MEDIUM | changedetectionio/tests/test_llm_api_key_security.py | 754 | # Create a real watch — required to exercise llm_clear_summary_cache's | COMMENT |
| MEDIUM | changedetectionio/tests/test_llm_token_budget.py | 67 | # Create a watch via API | COMMENT |
| MEDIUM | changedetectionio/tests/test_tag_url_match.py | 22 | # Create a tag with a URL match pattern | COMMENT |
| MEDIUM | changedetectionio/tests/test_api.py | 65 | # Create a watch | STRING |
| MEDIUM | changedetectionio/tests/test_api.py | 635 | # Create a watch | COMMENT |
| MEDIUM | changedetectionio/tests/test_api.py | 1014 | # Create a watch in restock_diff mode WITH processor_config in the POST body (matches the API docs example) | COMMENT |
| MEDIUM | changedetectionio/tests/test_api.py | 1198 | # Create a watch | COMMENT |
| MEDIUM | …detectionio/tests/test_settings_tag_force_reprocess.py | 99 | # Create a tag | STRING |
| MEDIUM | …detectionio/tests/test_settings_tag_force_reprocess.py | 169 | # Create a tag | STRING |
| MEDIUM | changedetectionio/tests/test_jinja2.py | 250 | # Create a large input string (over 10MB) | COMMENT |
| MEDIUM | changedetectionio/tests/test_jinja2.py | 286 | # Create a template with the dangerous pattern | COMMENT |
| MEDIUM | changedetectionio/tests/test_api_tags.py | 100 | # Create a watch with the tag and check it matches UUID | COMMENT |
| MEDIUM | changedetectionio/tests/test_api_tags.py | 188 | # Create a tag with processor_config_restock_diff in a single POST (issue #3966) | COMMENT |
| MEDIUM | changedetectionio/tests/test_llm_change_summary.py | 78 | # Create a tag with llm_change_summary, AI set to On so its watches inherit it | COMMENT |
| MEDIUM | changedetectionio/tests/unit/test_watch_model.py | 225 | # Create a watch with large datastore (many watches) | COMMENT |
| MEDIUM | changedetectionio/tests/unit/test_conditions.py | 14 | # Create a temporary directory for the test datastore | COMMENT |
| MEDIUM | …ngedetectionio/tests/unit/test_temporary_watch_seed.py | 108 | # Create a watch and drop a preload bundle into its data_dir, as the Add Watch | COMMENT |
| MEDIUM | changedetectionio/realtime/socket_server.py | 202 | # Create a simplified watch data object to send to clients | COMMENT |
| MEDIUM | changedetectionio/realtime/socket_server.py | 413 | # Create a dedicated signal handler that will receive signals and emit them to clients | COMMENT |
| MEDIUM⚡ | changedetectionio/processors/__init__.py | 469 | # Create a processor instance to access config methods | COMMENT |
| MEDIUM | changedetectionio/processors/base.py | 35 | # Create a stable snapshot of the watch for processing | COMMENT |
| MEDIUM | changedetectionio/conditions/blueprint.py | 43 | # Create a temporary watch data structure with this single rule | COMMENT |
| MEDIUM | changedetectionio/conditions/blueprint.py | 54 | # Create a temporary application data structure for the rule check | COMMENT |
| MEDIUM | changedetectionio/conditions/__init__.py | 29 | # Define the extended operations dictionary | COMMENT |
| MEDIUM | changedetectionio/conditions/__init__.py | 145 | # Create the ruleset | COMMENT |
| MEDIUM | changedetectionio/model/__init__.py | 443 | # Create a cached version if it doesn't exist | COMMENT |
| MEDIUM | changedetectionio/model/Watch.py | 999 | # Create a smaller intermediate image (to reduce memory usage) | COMMENT |
| MEDIUM | changedetectionio/api/Watch.py | 109 | # Create a dict copy for JSON response (with lock for thread safety) | COMMENT |
| MEDIUM | changedetectionio/blueprint/ui/edit.py | 162 | # Create a processor instance to access config methods | COMMENT |
| MEDIUM | changedetectionio/blueprint/browser_steps/__init__.py | 438 | # Create the response with ETag | COMMENT |
| MEDIUM | changedetectionio/blueprint/backups/__init__.py | 61 | # Create a list file with just the URLs, so it's easier to port somewhere else in the future | COMMENT |
| MEDIUM | changedetectionio/store/__init__.py | 59 | # Initialize parent class | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/pluggy_interface.py | 244 | CODE | |
| LOW | changedetectionio/pluggy_interface.py | 371 | CODE | |
| LOW | changedetectionio/pluggy_interface.py | 563 | CODE | |
| LOW | changedetectionio/worker.py | 47 | CODE | |
| LOW | changedetectionio/worker_pool.py | 134 | CODE | |
| LOW | changedetectionio/worker_pool.py | 519 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 237 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 281 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 311 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 347 | CODE | |
| LOW | changedetectionio/gc_cleanup.py | 12 | CODE | |
| LOW | changedetectionio/__init__.py | 199 | CODE | |
| LOW | changedetectionio/forms.py | 131 | CODE | |
| LOW | changedetectionio/forms.py | 682 | CODE | |
| LOW | changedetectionio/html_tools.py | 332 | CODE | |
| LOW | changedetectionio/html_tools.py | 375 | CODE | |
| LOW | changedetectionio/html_tools.py | 613 | CODE | |
| LOW | changedetectionio/html_tools.py | 723 | CODE | |
| LOW | changedetectionio/html_tools.py | 913 | CODE | |
| LOW | changedetectionio/auth_decorator.py | 16 | CODE | |
| LOW | changedetectionio/auth_decorator.py | 23 | CODE | |
| LOW | changedetectionio/custom_queue.py | 91 | CODE | |
| LOW | changedetectionio/custom_queue.py | 155 | CODE | |
| LOW | changedetectionio/custom_queue.py | 249 | CODE | |
| LOW | changedetectionio/custom_queue.py | 414 | CODE | |
| LOW | changedetectionio/custom_queue.py | 496 | CODE | |
| LOW | changedetectionio/languages.py | 166 | CODE | |
| LOW | changedetectionio/flask_app.py | 772 | CODE | |
| LOW | changedetectionio/flask_app.py | 1591 | CODE | |
| LOW | changedetectionio/flask_app.py | 1666 | CODE | |
| LOW | changedetectionio/flask_app.py | 853 | CODE | |
| LOW | changedetectionio/flask_app.py | 1140 | CODE | |
| LOW | changedetectionio/flask_app.py | 1450 | CODE | |
| LOW | changedetectionio/translations_overlay/manage.py | 53 | CODE | |
| LOW | changedetectionio/llm/client.py | 79 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 39 | CODE | |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 278 | CODE | |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 427 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 24 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 63 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 81 | CODE | |
| LOW | changedetectionio/content_fetchers/base.py | 208 | CODE | |
| LOW | changedetectionio/notification/handler.py | 151 | CODE | |
| LOW | changedetectionio/notification/handler.py | 207 | CODE | |
| LOW | changedetectionio/notification/handler.py | 306 | CODE | |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 56 | CODE | |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 200 | CODE | |
| LOW | changedetectionio/tests/conftest.py | 43 | CODE | |
| LOW | changedetectionio/tests/conftest.py | 405 | CODE | |
| LOW | changedetectionio/tests/conftest.py | 440 | CODE | |
| LOW | changedetectionio/tests/util.py | 266 | CODE | |
| LOW | changedetectionio/tests/util.py | 303 | CODE | |
| LOW | changedetectionio/tests/test_history_consistency.py | 13 | CODE | |
| LOW | changedetectionio/tests/test_basic_socketio.py | 13 | CODE | |
| LOW | changedetectionio/tests/test_llm_summary_async.py | 103 | CODE | |
| LOW | changedetectionio/tests/test_pwa_manifest.py | 97 | CODE | |
| LOW | …ngedetectionio/tests/unit/test_auth_decorator_order.py | 50 | CODE | |
| LOW | changedetectionio/tests/unit/test_fetch_url_gate.py | 218 | CODE | |
| LOW | changedetectionio/tests/smtp/smtp-test-server.py | 17 | CODE | |
| LOW | changedetectionio/diff/__init__.py | 79 | CODE | |
| 86 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | .github/workflows/test-stack-reusable-workflow.yml | 164 | # Check if RSS is less than 100MB | COMMENT |
| LOW⚡ | changedetectionio/pluggy_interface.py | 289 | # Check if plugin has datastore attribute and it's not set | COMMENT |
| LOW | changedetectionio/pluggy_interface.py | 399 | # Check if the result has any meaningful data | COMMENT |
| LOW | changedetectionio/pluggy_interface.py | 596 | # Check if plugin has a templates directory | COMMENT |
| LOW⚡ | changedetectionio/worker.py | 757 | # Check if we should restart (only when idle, between jobs) | COMMENT |
| LOW⚡ | changedetectionio/worker.py | 766 | # Check if we should exit | COMMENT |
| LOW⚡ | changedetectionio/worker.py | 770 | # Check if we're in pytest environment - if so, be more gentle with logging | COMMENT |
| LOW⚡ | changedetectionio/worker_pool.py | 138 | # Check if we're in pytest environment - if so, be more gentle with logging | COMMENT |
| LOW⚡ | changedetectionio/worker_pool.py | 416 | # Check if we're in pytest environment - if so, be more gentle with logging | COMMENT |
| LOW | changedetectionio/queue_handlers.py | 458 | # Check if all notifications are muted | COMMENT |
| LOW | changedetectionio/queue_handlers.py | 482 | # Check if all notifications are muted | COMMENT |
| LOW | changedetectionio/gc_cleanup.py | 68 | # Check if lxml.etree is in use | COMMENT |
| LOW | changedetectionio/gc_cleanup.py | 95 | # Check if lxml.html is in use | COMMENT |
| LOW | changedetectionio/gc_cleanup.py | 117 | # Check if json module is being used and try to clear its cache | COMMENT |
| LOW | changedetectionio/__init__.py | 593 | # Check if we need to repeat | COMMENT |
| LOW | changedetectionio/html_tools.py | 285 | # Iterate over the list of XPath selectors | COMMENT |
| LOW | changedetectionio/time_handler.py | 78 | # Check if the current day matches the target day or overlaps due to duration | COMMENT |
| LOW | changedetectionio/languages.py | 179 | # Check if messages.po exists | COMMENT |
| LOW | changedetectionio/flask_app.py | 647 | # Check if it's a built-in fetcher | COMMENT |
| LOW | changedetectionio/flask_app.py | 1012 | # Check if there's a redirect parameter to return to after re-login | COMMENT |
| LOW | changedetectionio/flask_app.py | 1046 | # Check if there's a redirect parameter to return to the same page | COMMENT |
| LOW | changedetectionio/flask_app.py | 1264 | # Check if file exists in plugin's static directory | COMMENT |
| LOW | changedetectionio/flask_app.py | 1741 | # Check if all checks are paused - this loop could get stuck on very long lists of watches, best to check he | COMMENT |
| LOW⚡ | changedetectionio/browser_steps/browser_steps.py | 146 | # Check if navigation actually occurred | COMMENT |
| LOW | changedetectionio/browser_steps/browser_steps.py | 124 | # Check if action handler exists | COMMENT |
| LOW | changedetectionio/browser_steps/browser_steps.py | 490 | # Check if session has expired based on age | COMMENT |
| LOW | changedetectionio/content_fetchers/playwright.py | 57 | # Set viewport to a larger size to capture more content at once | COMMENT |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 43 | # Check if body contains our diff placeholders | COMMENT |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 116 | # Check if we're approaching the embed count limit | COMMENT |
| LOW | …angedetectionio/notification/apprise_plugin/discord.py | 127 | # Check if adding this embed would exceed total character limit | COMMENT |
| LOW | changedetectionio/tests/test_commit_persistence.py | 437 | # Set browser_steps to meaningless values | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 192 | # Set language to Italian | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 702 | # Set language to German | COMMENT |
| LOW | changedetectionio/tests/test_rss_tag_token.py | 27 | # Assign tag to watch | COMMENT |
| LOW | changedetectionio/tests/unit/test_time_handler.py | 94 | # Set schedule to start 23:30 with 120 minute duration (crosses midnight) | COMMENT |
| LOW | changedetectionio/tests/unit/test_time_handler.py | 177 | # Set time to current hour | COMMENT |
| LOW | changedetectionio/tests/unit/test_time_handler.py | 513 | # Set time to 3 hours ago | COMMENT |
| LOW | changedetectionio/diff/__init__.py | 135 | # Check if there are any changes | COMMENT |
| LOW | changedetectionio/diff/__init__.py | 141 | # Check if the whole line is replaced (no unchanged content) | COMMENT |
| LOW | changedetectionio/diff/__init__.py | 270 | # Check if there are any changes | COMMENT |
| LOW | changedetectionio/diff/__init__.py | 406 | # Check if there are any actual changes (not just whitespace when ignore_junk is enabled) | COMMENT |
| LOW | changedetectionio/realtime/events.py | 22 | # Check if watch exists | COMMENT |
| LOW | changedetectionio/realtime/socket_server.py | 379 | # Check if authentication is required and user is not authenticated | COMMENT |
| LOW⚡ | changedetectionio/processors/__init__.py | 205 | # Check if DISABLED_PROCESSORS env var is set | COMMENT |
| LOW | changedetectionio/processors/__init__.py | 222 | # Check if this is a plugin processor | COMMENT |
| LOW | …ngedetectionio/processors/image_ssim_diff/processor.py | 62 | # Check if bounding box is set (for drawn area mode) | COMMENT |
| LOW | …ngedetectionio/processors/image_ssim_diff/processor.py | 146 | # Check if this is the first check (no previous history) | COMMENT |
| LOW | …ngedetectionio/processors/image_ssim_diff/edit_hook.py | 38 | # Check if template matching is globally enabled via ENV var | COMMENT |
| LOW | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 45 | # Check if decoding succeeded | COMMENT |
| LOW | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 150 | # Check if result is an error dict | COMMENT |
| LOW | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 306 | # Check if result is an error dict | COMMENT |
| LOW | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 436 | # Check if result is an error dict | COMMENT |
| LOW | …ssors/image_ssim_diff/image_handler/isolated_opencv.py | 581 | # Check if result is an error dict | COMMENT |
| LOW | …ssors/image_ssim_diff/image_handler/libvips_handler.py | 285 | # Check if match is good enough (80% confidence threshold) | COMMENT |
| LOW | …ngedetectionio/processors/text_json_diff/difference.py | 152 | # Check if this is a user submission (any diff pref param exists in query string) | COMMENT |
| LOW | …angedetectionio/processors/text_json_diff/processor.py | 184 | # Check if it's perl-style regex /.../ | COMMENT |
| LOW | …ionio/processors/restock_diff/pure_python_extractor.py | 38 | # Check if this is a JSON-LD script tag | COMMENT |
| LOW | changedetectionio/model/__init__.py | 313 | # Check if we're being initialized from an existing watch object | COMMENT |
| LOW | changedetectionio/model/__init__.py | 455 | # Check if it's a property descriptor | COMMENT |
| LOW | changedetectionio/model/Watch.py | 630 | # Check if binary file (image, PDF, etc.) | COMMENT |
| 10 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | changedetectionio/forms.py | 605 | f"The following tokens used in the notification are not valid: {undefined}" | CODE |
| HIGH | changedetectionio/notification/handler.py | 477 | #@todo on null:// (only if its a 1 url with null) probably doesnt need to actually .add/setup/etc | COMMENT |
| HIGH | changedetectionio/tests/test_jsonpath_jq_selector.py | 179 | nested = ('{"count": 3, "flag": null, "ok": true, ' | STRING |
| HIGH | changedetectionio/tests/test_api_security.py | 499 | # Should accept (empty is valid as null) | STRING |
| HIGH | changedetectionio/tests/test_api.py | 1231 | - CREATE endpoint rejects null, empty, and invalid URLs | STRING |
| HIGH | changedetectionio/tests/test_api.py | 1232 | - UPDATE endpoint rejects attempts to change URL to null, empty, or invalid | STRING |
| HIGH | changedetectionio/tests/test_xpath_selector_unit.py | 142 | ("manager[1]/@name || manager[2]/@name", "GodotFreya"), | CODE |
| HIGH⚡ | changedetectionio/tests/test_llm_change_summary.py | 159 | return JSON {"summary": null, "error": "<readable message>"} with a 500 | STRING |
| HIGH⚡ | changedetectionio/tests/llm/test_response_parser.py | 231 | raw = '{"needs_prefilter": false, "selector": null, "reason": "intent is global"}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_response_parser.py | 237 | raw = '{"needs_prefilter": "false", "selector": null, "reason": "global"}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 141 | llm_json = '{"price": null, "currency": null, "availability": "instock"}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 151 | llm_json = '{"price": 19.95, "currency": "GBP", "availability": null}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 161 | llm_json = '{"price": null, "currency": null, "availability": null}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 213 | llm_json = '{"price": null, "currency": null, "availability": null}' | CODE |
| HIGH | changedetectionio/api/Import.py | 43 | - anyOf: [{type: string}, {type: null}] (anyOf format) | STRING |
| HIGH⚡ | changedetectionio/blueprint/ui/diff.py | 494 | 202 {"summary": null, "status": "pending", still generating | STRING |
| HIGH⚡ | changedetectionio/blueprint/ui/diff.py | 496 | 200 {"summary": null, "status": "idle"} nothing running - re-POST | STRING |
| HIGH⚡ | changedetectionio/blueprint/ui/diff.py | 497 | 4xx/5xx {"summary": null, "error": "...", "status": "error"} the job failed | STRING |
| HIGH | changedetectionio/blueprint/ui/diff.py | 369 | 202 {"summary": null, "status": "pending", generating, poll the GET | STRING |
| HIGH | changedetectionio/blueprint/ui/diff.py | 371 | 4xx/5xx {"summary": null, "error": "...", "status": "error"} cannot be generated | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | changedetectionio/tests/test_ignore.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | …ngedetectionio/tests/test_trigger_regex_with_filter.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_ignorestatuscode.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | …angedetectionio/tests/test_block_while_text_present.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_conditions.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_ignorewhitespace.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_trigger_regex.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_ignore_text.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_trigger.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_restock_itemprop.py | 0 | <html> <body> some new nice initial text<br> <p>which is across multiple lines</p> <br> add to cart <br> so let's see wh | STRING |
| HIGH | changedetectionio/tests/test_extract_regex.py | 0 | <html> <body> some initial text<br> <p>which is across multiple lines</p> <br> so let's see what happens. <br> <div id=" | STRING |
| HIGH | …etectionio/tests/test_automatic_follow_ldjson_price.py | 0 | <html> <body> some initial text<br> <p>which is across multiple lines</p> <br> so let's see what happens. <br> <div id=" | STRING |
| HIGH | changedetectionio/tests/test_xpath_selector.py | 0 | <html> <body> some initial text<br> <p>which is across multiple lines</p> <br> so let's see what happens. <br> <div id=" | STRING |
| HIGH | changedetectionio/tests/test_css_selector.py | 0 | <html> <body> some initial text<br> <p>which is across multiple lines</p> <br> so let's see what happens. <br> <div id=" | STRING |
| HIGH | changedetectionio/tests/test_api.py | 0 | <html> <body> some initial text<br> <p>which is across multiple lines</p> <br> so let's see what happens. <br> <div id=" | STRING |
| HIGH | changedetectionio/api/Tags.py | 0 | background thread to queue all watches - discarded after completion. | STRING |
| HIGH | changedetectionio/blueprint/ui/__init__.py | 0 | background thread to queue all watches - discarded after completion. | STRING |
| HIGH | changedetectionio/api/Watch.py | 0 | background thread to queue all watches - discarded after completion. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | requirements.txt | 61 | beautifulsoup4<=4.15.0,>=4.15.0 | COMMENT |
| LOW | docker-entrypoint.sh | 1 | #!/bin/bash | COMMENT |
| LOW | docker-compose.yml | 1 | services: | COMMENT |
| LOW | docker-compose.yml | 21 | # Example: Install the OSINT reconnaissance processor plugin | COMMENT |
| LOW | docker-compose.yml | 41 | # | COMMENT |
| LOW | docker-compose.yml | 61 | # - HIDE_REFERER=true | COMMENT |
| LOW | docker-compose.yml | 81 | # | COMMENT |
| LOW | docker-compose.yml | 101 | # | COMMENT |
| LOW | docker-compose.yml | 121 | COMMENT | |
| LOW | docker-compose.yml | 141 | # restart: unless-stopped | COMMENT |
| LOW | docker-compose.yml | 161 | # --headless | COMMENT |
| LOW | docs/api-spec.yaml | 861 | type: string | COMMENT |
| LOW | .github/workflows/codeql-analysis.yml | 1 | # For most projects, this workflow file will not need changing; you simply need | COMMENT |
| LOW | .github/workflows/codeql-analysis.yml | 61 | # 📚 https://git.io/JvXDl | COMMENT |
| LOW | .github/workflows/test-only.yml | 81 | persist-credentials: false | COMMENT |
| LOW | .github/actions/extract-memory-report/action.yml | 41 | # sed 's/.*Peak memory: //' | \ | COMMENT |
| LOW | changedetectionio/validate_url.py | 61 | return normalized | COMMENT |
| LOW | changedetectionio/__init__.py | 21 | # Note: store and changedetection_app are imported inside main() to avoid | COMMENT |
| LOW | changedetectionio/__init__.py | 41 | # - Consistent across all platforms (Windows already uses spawn by default) | COMMENT |
| LOW | changedetectionio/forms.py | 461 | self.message = message | COMMENT |
| LOW | changedetectionio/forms.py | 841 | url = StringField('URL', validators=[validateURL()]) | COMMENT |
| LOW | changedetectionio/forms.py | 881 | COMMENT | |
| LOW | changedetectionio/html_tools.py | 21 | # watch's page ends up inside another watch's snapshot. | COMMENT |
| LOW | changedetectionio/languages.py | 61 | # | COMMENT |
| LOW | changedetectionio/flask_app.py | 161 | # That gives deployments an optional overlay layer: a catalog holding only the handful of msgids | COMMENT |
| LOW | changedetectionio/flask_app.py | 221 | notification_debug_log = [] | COMMENT |
| LOW | changedetectionio/flask_app.py | 861 | # Handled by static_content handler | COMMENT |
| LOW | changedetectionio/llm/client.py | 21 | DEFAULT_TIMEOUT = int(os.getenv('LLM_TIMEOUT', 300)) | COMMENT |
| LOW | changedetectionio/llm/evaluator.py | 261 | return llm_client.DEFAULT_TIMEOUT | COMMENT |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 401 | # Re-use as much code from browser steps as possible so its the same | COMMENT |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 441 | try: | COMMENT |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 481 | # fetcher. The fetch dies at PUPPETEER_MAX_PROCESSING_TIMEOUT_SECONDS having | COMMENT |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 501 | # goto() happens to return. This app compares the text of the page the browser ends up on, | COMMENT |
| LOW | …ngedetectionio/content_fetchers/res/favicon-fetcher.js | 61 | // and a worker the whole time. Simply capping the total made it worse: giving up early | COMMENT |
| LOW | …etectionio/tests/test_automatic_follow_ldjson_price.py | 201 | COMMENT | |
| LOW | …etectionio/tests/test_automatic_follow_ldjson_price.py | 221 | # }, | COMMENT |
| LOW | changedetectionio/tests/test_restock_itemprop.py | 301 | # PROOF that the threshold is measured "since the PREVIOUS check" and NOT "since the first check": | COMMENT |
| LOW | changedetectionio/tests/proxy_list/conftest.py | 1 | #!/usr/bin/env python3 | COMMENT |
| LOW | changedetectionio/tests/custom_browser_url/__init__.py | 1 | # placeholder | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 61 | COMMENT | |
| LOW | changedetectionio/processors/restock_diff/processor.py | 81 | # Why Multiprocessing Fixes This: | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 101 | # ------------------- | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 441 | self.screenshot = self.fetcher.screenshot | COMMENT |
| LOW | changedetectionio/static/js/csrf.js | 1 | // Attach the CSRF token to every state-changing jQuery request. | COMMENT |
| LOW | changedetectionio/static/js/scrollable-title.js | 1 | // The watch title in the top menu is a horizontal scroll container (see | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 1 | @use "settings" as *; | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 21 | // the gradient to that edge and push it up by the bar's own offset, and the bar | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 101 | } | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 121 | // | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 141 | COMMENT | |
| LOW | changedetectionio/static/styles/scss/diff.scss | 161 | // viewports at three device pixel ratios that number is 0.813, 0.203 or | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 181 | // is sticky it is invisible, and a device-pixel diff of the seam band at | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 201 | #diff-header { | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 221 | align-self: stretch; | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 241 | // | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 261 | // A centered flex item is sized to fit-content, which has a min-content | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 281 | // which is how a phone showed one row in a screenshot and a vertical stack in | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 301 | // label - measures over it and wraps to three. Neutralising just that rule | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 321 | // then taller than 50svh minus the top menu. With overflow: auto on the bar | COMMENT |
| LOW | changedetectionio/static/styles/scss/diff.scss | 481 | } | COMMENT |
| 14 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | changedetectionio/is_safe_url.py | 22 | Validate that a redirect URL is safe to prevent open redirect vulnerabilities. This follows Flask/Werkzeug bes | STRING |
| HIGH | changedetectionio/queue_handlers.py | 172 | Efficient async get using executor for blocking call. HYBRID APPROACH: Best of both worlds - U | STRING |
| HIGH | changedetectionio/diff/tokenizers/natural_text.py | 12 | Split text into words using simple whitespace boundaries. This is a simpler tokenizer that treats all whitespa | STRING |
| HIGH | changedetectionio/diff/tokenizers/words_and_html.py | 14 | Split text into words and boundaries (spaces, HTML tags). This tokenizer preserves HTML tags as atomic units w | STRING |
| HIGH | changedetectionio/processors/restock_diff/processor.py | 206 | Extract itemprop availability with hybrid approach for memory efficiency. Strategy (fastest to slowest, least | STRING |
| HIGH | changedetectionio/jinja2_custom/plugins/datetime_fmt.py | 87 | Format a Unix timestamp as a human-readable datetime. Args: value: timestamp as int/float/string, or t | STRING |
| HIGH | changedetectionio/model/persistence.py | 13 | Determine entity type from class hierarchy (cached at class level). Args: cls: The class to inspect | STRING |
| HIGH | changedetectionio/model/Watch.py | 56 | Save compressed data using native brotli with streaming compression. Uses chunked compression to minimize peak | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | changedetectionio/forms.py | 1113 | self.time_schedule_limit.form.timezone.render_kw['placeholder'] = default_tz | CODE |
| LOW⚡ | changedetectionio/forms.py | 1119 | proxy_name = StringField(_l('Name'), [validators.Optional()], render_kw={"placeholder": _l("Name")}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 1128 | ], render_kw={"placeholder": "socks5:// or regular proxy http://user:pass@...:3128", "size":50}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 1131 | browser_name = StringField(_l('Name'), [validators.Optional()], render_kw={"placeholder": _l("Name")}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 1140 | ], render_kw={"placeholder": "wss://brightdata... wss://oxylabs etc", "size":50}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 1143 | html_requests = StringField(_l('Plaintext requests'), validators=[validators.Optional()], render_kw={"placeholder": | CODE |
| LOW⚡ | changedetectionio/forms.py | 1145 | html_webdriver = StringField(_l('Chrome requests'), validators=[validators.Optional()], render_kw={"placeholder" | CODE |
| LOW⚡ | changedetectionio/forms.py | 1316 | render_kw={"placeholder": "5", "style": "width: 6em;"}, | CODE |
| LOW⚡ | changedetectionio/forms.py | 1323 | "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT, | CODE |
| LOW⚡ | changedetectionio/forms.py | 1333 | "placeholder": "0 = unlimited", | CODE |
| LOW | changedetectionio/forms.py | 923 | render_kw={"placeholder": os.getenv('BASE_URL', _l('Not set'))}) | CODE |
| LOW | changedetectionio/forms.py | 938 | selector = StringField(_l('Selector'), [validators.Optional()], render_kw={"placeholder": _l("CSS or xPath selector" | CODE |
| LOW | changedetectionio/forms.py | 939 | optional_value = StringField(_l('value'), [validators.Optional()], render_kw={"placeholder": _l("Value")}) | CODE |
| LOW | changedetectionio/forms.py | 963 | render_kw={"rows": "5", "placeholder": LLM_INTENT_WATCH_PLACEHOLDER}) | CODE |
| LOW | changedetectionio/forms.py | 966 | render_kw={"rows": "5", "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT}, | CODE |
| LOW | changedetectionio/forms.py | 1197 | render_kw={"placeholder": os.getenv('BASE_URL', _l('Not set'))} | CODE |
| LOW | changedetectionio/forms.py | 1213 | render_kw={"placeholder": "0.1", "style": "width: 8em;"} | CODE |
| LOW | changedetectionio/forms.py | 1224 | rss_template_override = TextAreaField(_l('RSS "System default" template override'), render_kw={"rows": "5", "placeho | CODE |
| LOW | changedetectionio/forms.py | 1263 | render_kw={"placeholder": "gpt-4o-mini", "style": "width: 24em;"}, | CODE |
| LOW | changedetectionio/forms.py | 1293 | "placeholder": "http://localhost:11434 (Ollama / custom endpoints only)", | CODE |
| LOW | changedetectionio/forms.py | 1348 | "placeholder": "100000", | CODE |
| LOW | changedetectionio/tests/test_llm_token_budget.py | 132 | "llm_evaluation_cache": {"fake_key": {"important": True}}, | CODE |
| LOW | changedetectionio/processors/image_ssim_diff/forms.py | 52 | render_kw={"placeholder": "Use global default (0.1)"} | CODE |
| LOW⚡ | changedetectionio/processors/restock_diff/forms.py | 22 | render_kw={"placeholder": _l("No limit"), "size": "10"}) | CODE |
| LOW⚡ | changedetectionio/processors/restock_diff/forms.py | 24 | render_kw={"placeholder": _l("No limit"), "size": "10"}) | CODE |
| LOW⚡ | changedetectionio/processors/restock_diff/forms.py | 29 | ], render_kw={"placeholder": "0%", "size": "5"}) | CODE |
| LOW | changedetectionio/static/js/scheduler.js | 35 | $('#local-time-in-tz').text(getTimeInTimezone(timezone_text_widget.attr('placeholder'))); | CODE |
| LOW | changedetectionio/conditions/form.py | 23 | value = StringField(_l("Value"), validators=[validators.Optional()], render_kw={"placeholder": _l("A value")}) | CODE |
| LOW | …angedetectionio/templates/edit/include_llm_intent.html | 164 | {% set summary_placeholder = form.llm_change_summary.render_kw['placeholder'] %} | CODE |
| LOW | changedetectionio/blueprint/tags/form.py | 25 | render_kw={"placeholder": _l("e.g. *://example.com/* or github.com/myorg")}) | CODE |
| LOW | changedetectionio/blueprint/tags/form.py | 49 | render_kw={"rows": "5", "placeholder": LLM_INTENT_TAG_PLACEHOLDER}) | CODE |
| LOW | changedetectionio/blueprint/tags/form.py | 53 | render_kw={"rows": "5", "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT}, | CODE |
| LOW | changedetectionio/blueprint/tags/form.py | 67 | name = StringField(_l('Tag name'), [validators.InputRequired()], render_kw={"placeholder": _l("Name")}) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/worker.py | 492 | # Step 1: AI Change Intent — may suppress notification | COMMENT |
| LOW | changedetectionio/worker.py | 513 | # Step 2: AI Change Summary — only compute it when a notification | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 465 | # Step 3: Queue watches for recheck (if -r was provided) | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 504 | # Step 4: Setup batch mode monitor (if -b was provided) | COMMENT |
| LOW | changedetectionio/__init__.py | 428 | # Step 1: Add URLs with their options (if provided via -u flags) | COMMENT |
| LOW | changedetectionio/__init__.py | 448 | # Step 2: Queue newly added watches (if -u was provided in batch mode) | COMMENT |
| LOW⚡ | changedetectionio/tests/test_extract_regex.py | 477 | # Step 1: keep lines containing "price" (excludes Stock count and Shipping cost) | COMMENT |
| LOW⚡ | changedetectionio/tests/test_extract_regex.py | 479 | # Step 2: from those lines extract only dollar amounts | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 91 | # Step 1: Set the language to Italian using the /set-language endpoint | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 99 | # Step 2: Request the index page - should be in Italian | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 629 | # Step 2: User explicitly selects Korean language | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 638 | # Step 3: Make another request with same zh-TW header | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 118 | # Step 3: Switch back to English | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 611 | # Step 1: Clear session and make first request with zh-TW header (auto-detect) | COMMENT |
| LOW⚡ | changedetectionio/processors/restock_diff/processor.py | 246 | # Step 2: Fall back to extruct (uses lxml, needs subprocess on Linux) | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 225 | # Step 1: Try pure Python extraction first (fast, no lxml, no memory leak) | COMMENT |
| LOW | changedetectionio/model/__init__.py | 170 | # IMPORTANT: Don't initialize __watch_was_edited yet! | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 60 | # Step 1: Escape everything like Jinja2 would (this makes it XSS-safe) | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 63 | # Step 2: Unescape only our exact diff spans generated by apply_html_color_to_body() | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/worker.py | 492 | # Step 1: AI Change Intent — may suppress notification | COMMENT |
| LOW | changedetectionio/worker.py | 513 | # Step 2: AI Change Summary — only compute it when a notification | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 465 | # Step 3: Queue watches for recheck (if -r was provided) | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 504 | # Step 4: Setup batch mode monitor (if -b was provided) | COMMENT |
| LOW | changedetectionio/__init__.py | 428 | # Step 1: Add URLs with their options (if provided via -u flags) | COMMENT |
| LOW | changedetectionio/__init__.py | 448 | # Step 2: Queue newly added watches (if -u was provided in batch mode) | COMMENT |
| LOW⚡ | changedetectionio/tests/test_extract_regex.py | 477 | # Step 1: keep lines containing "price" (excludes Stock count and Shipping cost) | COMMENT |
| LOW⚡ | changedetectionio/tests/test_extract_regex.py | 479 | # Step 2: from those lines extract only dollar amounts | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 91 | # Step 1: Set the language to Italian using the /set-language endpoint | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 99 | # Step 2: Request the index page - should be in Italian | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 629 | # Step 2: User explicitly selects Korean language | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 638 | # Step 3: Make another request with same zh-TW header | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 118 | # Step 3: Switch back to English | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 611 | # Step 1: Clear session and make first request with zh-TW header (auto-detect) | COMMENT |
| LOW⚡ | changedetectionio/processors/restock_diff/processor.py | 246 | # Step 2: Fall back to extruct (uses lxml, needs subprocess on Linux) | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 225 | # Step 1: Try pure Python extraction first (fast, no lxml, no memory leak) | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 60 | # Step 1: Escape everything like Jinja2 would (this makes it XSS-safe) | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 63 | # Step 2: Unescape only our exact diff spans generated by apply_html_color_to_body() | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | changedetectionio/static/js/jquery-3.6.0.min.js | 2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):f | CODE |
| CRITICAL | changedetectionio/blueprint/settings/__init__.py | 70 | form.application.form.notification_format.choices.pop() | CODE |
| CRITICAL | changedetectionio/blueprint/settings/__init__.py | 78 | form.requests.form.proxy.choices.append(tuple((p, datastore.proxy_list[p]['label']))) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/forms.py | 273 | CODE | |
| LOW | changedetectionio/content_fetchers/playwright.py | 250 | CODE | |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 674 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 210 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 63 | CODE | |
| LOW | changedetectionio/content_fetchers/base.py | 165 | CODE | |
| LOW | changedetectionio/tests/conftest.py | 322 | CODE | |
| LOW | changedetectionio/tests/util.py | 421 | CODE | |
| LOW | changedetectionio/diff/__init__.py | 309 | CODE | |
| LOW | changedetectionio/diff/__init__.py | 424 | CODE | |
| LOW | changedetectionio/processors/extract.py | 69 | CODE | |
| LOW | …ngedetectionio/processors/text_json_diff/difference.py | 247 | CODE | |
| LOW | changedetectionio/model/Watch.py | 792 | CODE | |
| LOW | changedetectionio/model/Watch.py | 1362 | CODE | |
| LOW | changedetectionio/blueprint/ui/preview.py | 126 | CODE | |
| LOW | changedetectionio/blueprint/ui/__init__.py | 227 | CODE | |
| LOW | changedetectionio/blueprint/settings/__init__.py | 289 | CODE | |
| LOW | changedetectionio/blueprint/settings/__init__.py | 306 | CODE | |
| LOW | changedetectionio/blueprint/imports/__init__.py | 84 | CODE | |
| LOW | changedetectionio/blueprint/tags/__init__.py | 40 | CODE | |
| LOW | changedetectionio/blueprint/tags/__init__.py | 239 | CODE | |
| LOW | changedetectionio/blueprint/backups/__init__.py | 177 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | changedetectionio/worker_pool.py | 361 | """Bulletproof queue operation with comprehensive error handling""" | STRING |
| LOW | changedetectionio/html_tools.py | 617 | # Foreach <script json></script> blob.. just return the first that matches json_filter | COMMENT |
| LOW | changedetectionio/flask_app.py | 386 | # by a shared cache under the long-lived header static_content() just set. | COMMENT |
| LOW | changedetectionio/content_fetchers/__init__.py | 170 | # What it referenced doesn't exist, just use a default | COMMENT |
| LOW | changedetectionio/content_fetchers/requests.py | 197 | # Binary files just return their checksum until we add something smarter | COMMENT |
| LOW | changedetectionio/notification/__init__.py | 8 | # But to avoid importing the whole heavy module just use the same strings here. | COMMENT |
| LOW | changedetectionio/tests/test_request.py | 9 | # Hard to just add more live server URLs when one test is already running (I think) | COMMENT |
| MEDIUM | changedetectionio/tests/test_history_consistency.py | 49 | # Essentially just triggers the DB write/update | COMMENT |
| LOW | changedetectionio/tests/test_notification.py | 23 | # Hard to just add more live server URLs when one test is already running (I think) | COMMENT |
| MEDIUM | changedetectionio/processors/magic.py | 64 | # Remove whitespace between < and tag name for robust detection (handles '< html', '<\nhtml', etc.) | COMMENT |
| LOW | changedetectionio/conditions/blueprint.py | 35 | # We'll ignore the returned response and just use the datastore which is modified by the function | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | changedetectionio/forms.py | 1306 | # DeepSeek-R1, Gemma 3, etc.) which emit chain-of-thought into | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 168 | # Models that emit chain-of-thought before the answer, on any provider. Reasoning tokens are | COMMENT |
| MEDIUM | …edetectionio/tests/test_settings_notifications_page.py | 55 | # The page uses the same tab UI scaffolding as /settings so the page styles | COMMENT |
| MEDIUM | changedetectionio/blueprint/settings/llm.py | 191 | # headroom needed for chain-of-thought to complete. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/diff/__init__.py | 511 | __all__ = [ | CODE |
| LOW | changedetectionio/diff/tokenizers/__init__.py | 19 | __all__ = [ | CODE |
| LOW | changedetectionio/jinja2_custom/__init__.py | 15 | __all__ = [ | CODE |
| LOW | changedetectionio/jinja2_custom/plugins/__init__.py | 7 | __all__ = ['regex_replace', 'unixtime'] | CODE |
| LOW | changedetectionio/model/__init__.py | 7 | __all__ = ['EntityPersistenceMixin', 'watch_base'] | CODE |
| LOW | changedetectionio/widgets/__init__.py | 3 | __all__ = ['TernaryNoneBooleanWidget', 'TernaryNoneBooleanField'] | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/content_fetchers/__init__.py | 48 | # In this case, make sure to edit the default one in store.py and fetch_site_status.py | COMMENT |