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 presents the forensic synthetic code analysis of dgtlmoon/changedetection.io, a Python project with 32,305 GitHub stars. SynthScan v2.0 examined 91,782 lines of code across 438 source files, recording 2164 pattern matches distributed across 21 syntactic categories. The overall adjusted score of 36.0 places this repository in the Strong AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 2164 distinct pattern matches across 21 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. 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 diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| 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 | 576 | def get_plugin_template_paths(): | CODE |
| LOW | changedetectionio/pluggy_interface.py | 632 | def apply_update_handler_alter(update_handler, watch, datastore): | CODE |
| LOW⚡ | changedetectionio/worker.py | 771 | async def send_content_changed_notification(watch_uuid, notification_q, datastore): | CODE |
| LOW⚡ | changedetectionio/worker.py | 784 | async def send_filter_failure_notification(watch_uuid, notification_q, datastore): | CODE |
| LOW⚡ | changedetectionio/worker.py | 797 | async def send_step_failure_notification(watch_uuid, step_n, notification_q, datastore): | CODE |
| LOW | changedetectionio/worker.py | 31 | 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 | 129 | async def start_single_async_worker(worker_id, update_q, notification_q, app, datastore, executor=None): | CODE |
| LOW | changedetectionio/worker_pool.py | 218 | def claim_uuid_for_processing(uuid, worker_id): | CODE |
| LOW | changedetectionio/worker_pool.py | 243 | def release_uuid_from_processing(uuid, worker_id): | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 281 | def is_watch_running_by_another_worker(watch_uuid, current_worker_id): | CODE |
| LOW | changedetectionio/worker_pool.py | 377 | def adjust_async_worker_count(new_count, update_q=None, notification_q=None, app=None, datastore=None): | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 540 | def _emit_notification_signal(self, item: Dict[str, Any]): | CODE |
| LOW | changedetectionio/notification_service.py | 244 | def set_random_for_validation(self): | CODE |
| LOW | changedetectionio/notification_service.py | 262 | 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 | 327 | def set_basic_notification_vars(current_snapshot, prev_snapshot, watch, triggered_text, timestamp_changed=None): | CODE |
| LOW | changedetectionio/notification_service.py | 358 | def queue_notification_for_watch(self, n_object: NotificationContextData, watch, date_index_from=-2, date_index_to=- | CODE |
| LOW | changedetectionio/notification_service.py | 415 | def send_content_changed_notification(self, watch_uuid): | CODE |
| LOW | changedetectionio/notification_service.py | 459 | def send_filter_failure_notification(self, watch_uuid): | CODE |
| LOW | changedetectionio/notification_service.py | 506 | def send_step_failure_notification(self, watch_uuid, step_n): | STRING |
| LOW | changedetectionio/notification_service.py | 554 | def create_notification_service(datastore, notification_q): | STRING |
| LOW⚡ | changedetectionio/validate_url.py | 119 | def is_url_private_or_parser_confused(url): | CODE |
| LOW | changedetectionio/__init__.py | 516 | def queue_watches_for_recheck(datastore, iteration): | CODE |
| LOW | changedetectionio/forms.py | 802 | # def validate_notification_urls(self, field): | COMMENT |
| LOW | changedetectionio/forms.py | 223 | def validate_time_between_check_has_values(form): | CODE |
| LOW | changedetectionio/html_tools.py | 122 | def perl_style_slash_enclosed_regex_to_options(regex): | CODE |
| LOW | changedetectionio/html_tools.py | 171 | def subtractive_xpath_selector(selectors: List[str], html_content: str) -> str: | CODE |
| LOW | changedetectionio/html_tools.py | 440 | def _get_stripped_text_from_json_match(match): | CODE |
| LOW | changedetectionio/html_tools.py | 461 | def extract_json_blob_from_html(content, ensure_is_ldjson_info_type, json_filter): | CODE |
| LOW | changedetectionio/html_tools.py | 638 | def cdata_in_document_to_text(html_content: str, render_anchor_tag_content=False) -> str: | CODE |
| LOW | changedetectionio/html_tools.py | 728 | def workarounds_for_obfuscations(content): | CODE |
| LOW | changedetectionio/auth_decorator.py | 16 | def login_optionally_required(func): | CODE |
| LOW | changedetectionio/flask_app.py | 139 | def _configure_plugin_templates(): | CODE |
| LOW | changedetectionio/flask_app.py | 238 | def _get_watch_queue_position(watch_obj): | CODE |
| LOW | changedetectionio/flask_app.py | 244 | def _get_current_worker_count(): | CODE |
| LOW | changedetectionio/flask_app.py | 526 | def inject_llm_features_disabled(): | CODE |
| LOW | changedetectionio/flask_app.py | 704 | def before_request_handle_cookie_x_settings(): | CODE |
| LOW | changedetectionio/flask_app.py | 1112 | def ticker_thread_check_time_launch_checks(): | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 117 | def build_preview_system_prompt() -> str: | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 134 | def build_change_summary_prompt(diff: str, custom_prompt: str, | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 158 | def build_change_summary_system_prompt() -> str: | CODE |
| LOW | changedetectionio/llm/prompt_builder.py | 200 | def build_setup_system_prompt() -> str: | CODE |
| LOW⚡ | changedetectionio/llm/evaluator.py | 347 | def get_global_token_budget_month(datastore=None) -> int: | CODE |
| LOW⚡ | changedetectionio/llm/evaluator.py | 540 | def get_effective_summary_prompt(watch, datastore) -> str: | CODE |
| LOW | changedetectionio/llm/evaluator.py | 158 | def apply_local_token_multiplier(base_max_tokens: int, llm_cfg: dict) -> int: | CODE |
| LOW | changedetectionio/llm/evaluator.py | 427 | def is_global_token_budget_exceeded(datastore) -> bool: | CODE |
| LOW | changedetectionio/llm/evaluator.py | 552 | def compute_summary_cache_key(diff_text: str, prompt: str) -> str: | CODE |
| LOW | changedetectionio/llm/evaluator.py | 593 | def build_summary_cache_prompt(effective_prompt: str, max_summary_tokens: int, | CODE |
| LOW | changedetectionio/browser_steps/browser_steps.py | 11 | def browser_steps_get_valid_steps(browser_steps: list): | CODE |
| LOW | changedetectionio/browser_steps/browser_steps.py | 148 | async def action_click_element_containing_text(self, selector=None, value=''): | CODE |
| LOW | changedetectionio/browser_steps/browser_steps.py | 158 | async def action_click_element_containing_text_if_exists(self, selector=None, value=''): | CODE |
| LOW | changedetectionio/browser_steps/browser_steps.py | 170 | async def action_enter_text_in_field(self, selector, value): | CODE |
| 755 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/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 | 338 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 340 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 536 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 538 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 698 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 700 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 755 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/llm/evaluator.py | 757 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 236 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 238 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 279 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 281 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 445 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/llm/evaluator.py | 447 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 729 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 732 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 741 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 744 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 754 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 758 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 775 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 778 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 865 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 867 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 874 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 876 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 888 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 890 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 894 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 896 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 906 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_security.py | 908 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 692 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 694 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 711 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 714 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 921 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 924 | # --------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 74 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 76 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 144 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 146 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 210 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 212 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 244 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 246 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 299 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 301 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 348 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | changedetectionio/tests/test_llm_group_overrides.py | 350 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_llm_group_overrides.py | 23 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_llm_group_overrides.py | 25 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | changedetectionio/tests/test_llm_group_overrides.py | 50 | # --------------------------------------------------------------------------- | COMMENT |
| 130 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH⚡ | docs/api-spec.yaml | 1311 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH⚡ | docs/api-spec.yaml | 1315 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH⚡ | docs/api-spec.yaml | 1319 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH⚡ | docs/api-spec.yaml | 1324 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2023 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2029 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2035 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH⚡ | docs/api-spec.yaml | 2043 | '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 | 895 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 900 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 968 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 983 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1032 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1037 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1094 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1106 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1152 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1157 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1190 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1195 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1232 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1237 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1515 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1521 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1555 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1560 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1594 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1604 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1644 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1649 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1696 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1707 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1747 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1752 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1779 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1784 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 1804 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1817 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1858 | -H "x-api-key: YOUR_API_KEY" \ | CODE |
| HIGH | docs/api-spec.yaml | 1870 | 'x-api-key': 'YOUR_API_KEY', | CODE |
| HIGH | docs/api-spec.yaml | 1906 | -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 | 1951 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 1956 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH | docs/api-spec.yaml | 2122 | -H "x-api-key: YOUR_API_KEY" | CODE |
| HIGH | docs/api-spec.yaml | 2127 | headers = {'x-api-key': 'YOUR_API_KEY'} | CODE |
| HIGH⚡ | docs/api_v1/index.html | 974 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH⚡ | docs/api_v1/index.html | 978 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH⚡ | docs/api_v1/index.html | 982 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH | docs/api_v1/index.html | 471 | <p>For example: <code>x-api-key: YOUR_API_KEY</code></p> | CODE |
| HIGH | docs/api_v1/index.html | 473 | <p>For example: <code>x-api-key: YOUR_API_KEY</code></p> | CODE |
| HIGH | docs/api_v1/index.html | 495 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH | docs/api_v1/index.html | 659 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| HIGH | docs/api_v1/index.html | 803 | <span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span> | CODE |
| 27 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 | 547 | except Exception as e: | CODE |
| LOW | changedetectionio/pluggy_interface.py | 571 | except Exception as e: | CODE |
| LOW | changedetectionio/pluggy_interface.py | 688 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker.py | 780 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker.py | 793 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker.py | 806 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 120 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 135 | except Exception as health_e: | CODE |
| LOW | changedetectionio/worker.py | 403 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 511 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 567 | except Exception as _fe: | CODE |
| LOW | changedetectionio/worker.py | 584 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 602 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 615 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 642 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 665 | except Exception as e: | CODE |
| LOW | changedetectionio/worker.py | 689 | except Exception as cleanup_error: | CODE |
| LOW | changedetectionio/worker.py | 702 | except Exception as finalize_error: | CODE |
| LOW | changedetectionio/worker.py | 714 | 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 | 78 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 124 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 157 | except Exception as e: | CODE |
| LOW | changedetectionio/worker_pool.py | 188 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 298 | except Exception as uuid_e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 322 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 330 | except Exception as health_e: | CODE |
| LOW⚡ | changedetectionio/worker_pool.py | 336 | except Exception: | CODE |
| LOW | changedetectionio/worker_pool.py | 367 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 248 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 257 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 267 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 537 | except Exception as e: | CODE |
| LOW⚡ | changedetectionio/queue_handlers.py | 549 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 60 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 79 | except Exception as notif_e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 91 | except Exception as signal_e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 97 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 121 | except Exception as signal_e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 131 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 157 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 200 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 210 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 223 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 297 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 332 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 373 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 384 | except Exception: | CODE |
| LOW | changedetectionio/queue_handlers.py | 401 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 409 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 435 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 457 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 480 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 495 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 515 | except Exception as e: | CODE |
| LOW | changedetectionio/queue_handlers.py | 524 | except Exception as e: | CODE |
| LOW | changedetectionio/favicon_utils.py | 31 | except Exception: | CODE |
| 258 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/worker.py | 328 | CODE | |
| LOW | changedetectionio/worker.py | 404 | CODE | |
| LOW | changedetectionio/worker.py | 451 | 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 | 15 | CODE | |
| LOW | changedetectionio/forms.py | 508 | CODE | |
| LOW | changedetectionio/auth_decorator.py | 3 | CODE | |
| LOW | changedetectionio/auth_decorator.py | 4 | CODE | |
| LOW | changedetectionio/time_handler.py | 1 | CODE | |
| LOW | changedetectionio/languages.py | 5 | CODE | |
| LOW | changedetectionio/llm/evaluator.py | 39 | 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 | 105 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 98 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 101 | CODE | |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 10 | 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 | 309 | CODE | |
| LOW | changedetectionio/notification/handler.py | 311 | 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_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 | 3 | 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 | 390 | CODE | |
| LOW | changedetectionio/tests/test_ignore.py | 3 | CODE | |
| 243 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | .github/workflows/test-stack-reusable-workflow.yml | 416 | # Create a watch via API through nginx proxy subpath | COMMENT |
| MEDIUM | .github/workflows/test-stack-reusable-workflow.yml | 741 | # Create a watch with tag "github-group-test" via API | COMMENT |
| MEDIUM | .github/workflows/test-stack-reusable-workflow.yml | 755 | # 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 | 52 | # 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 | 309 | # 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 | 148 | # Create a ChoiceLoader that searches app templates first, then plugin templates | COMMENT |
| MEDIUM | changedetectionio/notification/handler.py | 110 | # Define the mapping between your placeholders and markdown markers | COMMENT |
| MEDIUM | changedetectionio/notification/handler.py | 134 | # Define the mapping between your placeholders and markdown markers | COMMENT |
| MEDIUM | changedetectionio/tests/test_security.py | 960 | # 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_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 | 618 | # 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 | 557 | # Create a watch | STRING |
| MEDIUM | changedetectionio/tests/test_api.py | 936 | # 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 | 1120 | # 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 | COMMENT |
| MEDIUM | changedetectionio/tests/unit/test_watch_model.py | 224 | # 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 | changedetectionio/realtime/socket_server.py | 158 | # Create a simplified watch data object to send to clients | COMMENT |
| MEDIUM | changedetectionio/realtime/socket_server.py | 345 | # Create a dedicated signal handler that will receive signals and emit them to clients | COMMENT |
| MEDIUM⚡ | changedetectionio/processors/__init__.py | 457 | # Create a processor instance to access config methods | COMMENT |
| MEDIUM | changedetectionio/processors/base.py | 33 | # 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 | 131 | # Create the ruleset | COMMENT |
| MEDIUM | changedetectionio/model/__init__.py | 440 | # Create a cached version if it doesn't exist | COMMENT |
| MEDIUM | changedetectionio/model/Watch.py | 943 | # Create a smaller intermediate image (to reduce memory usage) | COMMENT |
| MEDIUM | changedetectionio/api/Watch.py | 73 | # Create a dict copy for JSON response (with lock for thread safety) | COMMENT |
| MEDIUM | changedetectionio/blueprint/ui/edit.py | 135 | # Create a processor instance to access config methods | COMMENT |
| MEDIUM | changedetectionio/blueprint/browser_steps/__init__.py | 408 | # 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 | 54 | # 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 | 576 | CODE | |
| LOW | changedetectionio/worker.py | 46 | CODE | |
| LOW | changedetectionio/worker_pool.py | 129 | CODE | |
| LOW | changedetectionio/worker_pool.py | 449 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 227 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 271 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 301 | CODE | |
| LOW | changedetectionio/queue_handlers.py | 336 | CODE | |
| LOW | changedetectionio/gc_cleanup.py | 12 | CODE | |
| LOW | changedetectionio/__init__.py | 181 | CODE | |
| LOW | changedetectionio/forms.py | 124 | CODE | |
| LOW | changedetectionio/html_tools.py | 226 | CODE | |
| LOW | changedetectionio/html_tools.py | 268 | CODE | |
| LOW | changedetectionio/html_tools.py | 461 | CODE | |
| LOW | changedetectionio/html_tools.py | 571 | CODE | |
| LOW | changedetectionio/html_tools.py | 759 | 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 | 78 | CODE | |
| LOW | changedetectionio/flask_app.py | 464 | CODE | |
| LOW | changedetectionio/flask_app.py | 1058 | CODE | |
| LOW | changedetectionio/flask_app.py | 1112 | CODE | |
| LOW | changedetectionio/flask_app.py | 532 | CODE | |
| LOW | changedetectionio/flask_app.py | 746 | CODE | |
| LOW | changedetectionio/flask_app.py | 947 | CODE | |
| LOW | changedetectionio/llm/client.py | 66 | CODE | |
| LOW | changedetectionio/content_fetchers/__init__.py | 39 | 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 | 165 | CODE | |
| LOW | changedetectionio/notification/handler.py | 153 | CODE | |
| LOW | changedetectionio/notification/handler.py | 209 | CODE | |
| LOW | changedetectionio/notification/handler.py | 307 | 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 | 404 | CODE | |
| LOW | changedetectionio/tests/conftest.py | 439 | CODE | |
| LOW | changedetectionio/tests/util.py | 245 | CODE | |
| LOW | changedetectionio/tests/util.py | 257 | CODE | |
| LOW | changedetectionio/tests/test_history_consistency.py | 13 | CODE | |
| LOW | changedetectionio/tests/test_basic_socketio.py | 13 | CODE | |
| LOW | …ngedetectionio/tests/unit/test_auth_decorator_order.py | 43 | CODE | |
| LOW | changedetectionio/tests/smtp/smtp-test-server.py | 17 | CODE | |
| LOW | changedetectionio/diff/__init__.py | 79 | CODE | |
| LOW | changedetectionio/diff/__init__.py | 309 | CODE | |
| LOW | changedetectionio/diff/tokenizers/words_and_html.py | 13 | CODE | |
| LOW | changedetectionio/realtime/events.py | 6 | CODE | |
| LOW | changedetectionio/realtime/events.py | 10 | CODE | |
| LOW | changedetectionio/realtime/socket_server.py | 62 | CODE | |
| LOW | changedetectionio/processors/magic.py | 59 | CODE | |
| LOW | changedetectionio/processors/__init__.py | 21 | CODE | |
| 79 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | .github/workflows/test-stack-reusable-workflow.yml | 143 | # 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 | 609 | # Check if plugin has a templates directory | COMMENT |
| LOW⚡ | changedetectionio/worker.py | 738 | # Check if we should restart (only when idle, between jobs) | COMMENT |
| LOW⚡ | changedetectionio/worker.py | 747 | # Check if we should exit | COMMENT |
| LOW⚡ | changedetectionio/worker.py | 751 | # Check if we're in pytest environment - if so, be more gentle with logging | COMMENT |
| LOW⚡ | changedetectionio/worker_pool.py | 133 | # Check if we're in pytest environment - if so, be more gentle with logging | COMMENT |
| LOW⚡ | changedetectionio/worker_pool.py | 346 | # Check if we're in pytest environment - if so, be more gentle with logging | COMMENT |
| LOW | changedetectionio/queue_handlers.py | 447 | # Check if all notifications are muted | COMMENT |
| LOW | changedetectionio/queue_handlers.py | 471 | # 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 | 575 | # Check if we need to repeat | COMMENT |
| LOW | changedetectionio/html_tools.py | 179 | # Iterate over the list of XPath selectors | COMMENT |
| LOW | changedetectionio/time_handler.py | 55 | # Check if the current day matches the target day or overlaps due to duration | COMMENT |
| LOW | changedetectionio/languages.py | 91 | # Check if messages.po exists | COMMENT |
| LOW | changedetectionio/flask_app.py | 370 | # Check if it's a built-in fetcher | COMMENT |
| LOW | changedetectionio/flask_app.py | 623 | # Check if there's a redirect parameter to return to after re-login | COMMENT |
| LOW | changedetectionio/flask_app.py | 656 | # Check if there's a redirect parameter to return to the same page | COMMENT |
| LOW | changedetectionio/flask_app.py | 839 | # Check if file exists in plugin's static directory | COMMENT |
| LOW | changedetectionio/flask_app.py | 1145 | # Check if all checks are paused | COMMENT |
| LOW | changedetectionio/browser_steps/browser_steps.py | 90 | # Check if action handler exists | COMMENT |
| LOW⚡ | changedetectionio/browser_steps/browser_steps.py | 112 | # Check if navigation actually occurred | COMMENT |
| LOW | changedetectionio/browser_steps/browser_steps.py | 433 | # 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 | changedetectionio/content_fetchers/puppeteer.py | 383 | # Check if page still exists (might have been closed due to error during sleep) | COMMENT |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 413 | # Check if page still exists before sending command | 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 | 169 | # Set language to Italian | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 666 | # 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 | 319 | # Check if authentication is required and user is not authenticated | COMMENT |
| LOW⚡ | changedetectionio/processors/__init__.py | 204 | # Check if DISABLED_PROCESSORS env var is set | COMMENT |
| LOW | changedetectionio/processors/__init__.py | 221 | # 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 | 168 | # 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 | 37 | # Check if this is a JSON-LD script tag | COMMENT |
| LOW | changedetectionio/model/__init__.py | 310 | # Check if we're being initialized from an existing watch object | COMMENT |
| 13 more matches not shown… | ||||
| 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 |
|---|---|---|---|---|
| HIGH | changedetectionio/forms.py | 563 | f"The following tokens used in the notification are not valid: {undefined}" | CODE |
| HIGH | changedetectionio/notification/handler.py | 475 | #@todo on null:// (only if its a 1 url with null) probably doesnt need to actually .add/setup/etc | COMMENT |
| HIGH | changedetectionio/tests/test_api_security.py | 499 | # Should accept (empty is valid as null) | STRING |
| HIGH | changedetectionio/tests/test_api.py | 1153 | - CREATE endpoint rejects null, empty, and invalid URLs | STRING |
| HIGH | changedetectionio/tests/test_api.py | 1154 | - 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 | 158 | return JSON {"summary": null, "error": "<readable message>"} with a 500 | STRING |
| HIGH⚡ | changedetectionio/tests/llm/test_response_parser.py | 93 | raw = '{"needs_prefilter": false, "selector": null, "reason": "intent is global"}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 128 | llm_json = '{"price": null, "currency": null, "availability": "instock"}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 138 | llm_json = '{"price": 19.95, "currency": "GBP", "availability": null}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 148 | llm_json = '{"price": null, "currency": null, "availability": null}' | CODE |
| HIGH⚡ | changedetectionio/tests/llm/test_llm_restock_plugin.py | 200 | llm_json = '{"price": null, "currency": null, "availability": null}' | CODE |
| HIGH | changedetectionio/api/Import.py | 39 | - anyOf: [{type: string}, {type: null}] (anyOf format) | STRING |
| HIGH | changedetectionio/blueprint/ui/diff.py | 180 | Returns JSON: {"summary": "...", "error": null} or {"summary": null, "error": "..."} | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | changedetectionio/forms.py | 969 | self.time_schedule_limit.form.timezone.render_kw['placeholder'] = default_tz | CODE |
| LOW⚡ | changedetectionio/forms.py | 975 | proxy_name = StringField(_l('Name'), [validators.Optional()], render_kw={"placeholder": _l("Name")}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 984 | ], render_kw={"placeholder": "socks5:// or regular proxy http://user:pass@...:3128", "size":50}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 987 | browser_name = StringField(_l('Name'), [validators.Optional()], render_kw={"placeholder": _l("Name")}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 996 | ], render_kw={"placeholder": "wss://brightdata... wss://oxylabs etc", "size":50}) | CODE |
| LOW⚡ | changedetectionio/forms.py | 999 | html_requests = StringField(_l('Plaintext requests'), validators=[validators.Optional()], render_kw={"placeholder": | CODE |
| LOW⚡ | changedetectionio/forms.py | 1001 | html_webdriver = StringField(_l('Chrome requests'), validators=[validators.Optional()], render_kw={"placeholder" | CODE |
| LOW⚡ | changedetectionio/forms.py | 1149 | render_kw={"placeholder": "5", "style": "width: 6em;"}, | CODE |
| LOW⚡ | changedetectionio/forms.py | 1156 | "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT, | CODE |
| LOW⚡ | changedetectionio/forms.py | 1166 | "placeholder": "0 = unlimited", | CODE |
| LOW | changedetectionio/forms.py | 821 | selector = StringField(_l('Selector'), [validators.Optional()], render_kw={"placeholder": _l("CSS or xPath selector" | CODE |
| LOW | changedetectionio/forms.py | 822 | optional_value = StringField(_l('value'), [validators.Optional()], render_kw={"placeholder": _l("Value")}) | CODE |
| LOW | changedetectionio/forms.py | 845 | render_kw={"rows": "5", "placeholder": LLM_INTENT_WATCH_PLACEHOLDER}) | CODE |
| LOW | changedetectionio/forms.py | 848 | render_kw={"rows": "5", "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT}, | CODE |
| LOW | changedetectionio/forms.py | 1046 | render_kw={"placeholder": os.getenv('BASE_URL', _l('Not set'))} | CODE |
| LOW | changedetectionio/forms.py | 1062 | render_kw={"placeholder": "0.1", "style": "width: 8em;"} | CODE |
| LOW | changedetectionio/forms.py | 1073 | rss_template_override = TextAreaField(_l('RSS "System default" template override'), render_kw={"rows": "5", "placeho | CODE |
| LOW | changedetectionio/forms.py | 1112 | render_kw={"placeholder": "gpt-4o-mini", "style": "width: 24em;"}, | CODE |
| LOW | changedetectionio/forms.py | 1126 | "placeholder": "http://localhost:11434 (Ollama / custom endpoints only)", | CODE |
| LOW | changedetectionio/forms.py | 1181 | "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 | 91 | {% set summary_placeholder = form.llm_change_summary.render_kw['placeholder'] %} | CODE |
| LOW⚡ | changedetectionio/blueprint/tags/form.py | 18 | render_kw={"placeholder": _l("e.g. *://example.com/* or github.com/myorg")}) | CODE |
| LOW⚡ | changedetectionio/blueprint/tags/form.py | 22 | render_kw={"rows": "5", "placeholder": LLM_INTENT_TAG_PLACEHOLDER}) | CODE |
| LOW⚡ | changedetectionio/blueprint/tags/form.py | 26 | render_kw={"rows": "5", "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT}, | CODE |
| LOW⚡ | changedetectionio/blueprint/tags/form.py | 31 | name = StringField(_l('Tag name'), [validators.InputRequired()], render_kw={"placeholder": _l("Name")}) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/worker.py | 479 | # Step 1: AI Change Intent — may suppress notification | COMMENT |
| LOW | changedetectionio/worker.py | 500 | # Step 2: AI Change Summary — runs for any LLM-configured watch with a change | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 447 | # Step 3: Queue watches for recheck (if -r was provided) | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 486 | # Step 4: Setup batch mode monitor (if -b was provided) | COMMENT |
| LOW | changedetectionio/__init__.py | 410 | # Step 1: Add URLs with their options (if provided via -u flags) | COMMENT |
| LOW | changedetectionio/__init__.py | 430 | # 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 | 83 | # Step 1: Set the language to Italian using the /set-language endpoint | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 91 | # Step 2: Request the index page - should be in Italian | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 593 | # Step 2: User explicitly selects Korean language | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 602 | # Step 3: Make another request with same zh-TW header | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 105 | # Step 3: Switch back to English | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 575 | # Step 1: Clear session and make first request with zh-TW header (auto-detect) | COMMENT |
| LOW⚡ | changedetectionio/processors/restock_diff/processor.py | 244 | # Step 2: Fall back to extruct (uses lxml, needs subprocess on Linux) | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 223 | # 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 | 59 | # Step 1: Escape everything like Jinja2 would (this makes it XSS-safe) | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 62 | # 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 | 479 | # Step 1: AI Change Intent — may suppress notification | COMMENT |
| LOW | changedetectionio/worker.py | 500 | # Step 2: AI Change Summary — runs for any LLM-configured watch with a change | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 447 | # Step 3: Queue watches for recheck (if -r was provided) | COMMENT |
| LOW⚡ | changedetectionio/__init__.py | 486 | # Step 4: Setup batch mode monitor (if -b was provided) | COMMENT |
| LOW | changedetectionio/__init__.py | 410 | # Step 1: Add URLs with their options (if provided via -u flags) | COMMENT |
| LOW | changedetectionio/__init__.py | 430 | # 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 | 83 | # Step 1: Set the language to Italian using the /set-language endpoint | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 91 | # Step 2: Request the index page - should be in Italian | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 593 | # Step 2: User explicitly selects Korean language | COMMENT |
| LOW⚡ | changedetectionio/tests/test_i18n.py | 602 | # Step 3: Make another request with same zh-TW header | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 105 | # Step 3: Switch back to English | COMMENT |
| LOW | changedetectionio/tests/test_i18n.py | 575 | # Step 1: Clear session and make first request with zh-TW header (auto-detect) | COMMENT |
| LOW⚡ | changedetectionio/processors/restock_diff/processor.py | 244 | # Step 2: Fall back to extruct (uses lxml, needs subprocess on Linux) | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 223 | # Step 1: Try pure Python extraction first (fast, no lxml, no memory leak) | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 59 | # Step 1: Escape everything like Jinja2 would (this makes it XSS-safe) | COMMENT |
| LOW⚡ | changedetectionio/blueprint/ui/diff.py | 62 | # Step 2: Unescape only our exact diff spans generated by apply_html_color_to_body() | COMMENT |
| 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 | 162 | 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 | 204 | Extract itemprop availability with hybrid approach for memory efficiency. Strategy (fastest to slowest, least | 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 | 55 | Save compressed data using native brotli with streaming compression. Uses chunked compression to minimize peak | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | requirements.txt | 61 | beautifulsoup4>=4.0.0,<=4.14.3 | 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 | # Playwright proxy settings playwright_proxy_server, playwright_proxy_bypass, playwright_proxy_username, playwri | COMMENT |
| LOW | docker-compose.yml | 61 | # Default number of parallel/concurrent fetchers | COMMENT |
| LOW | docker-compose.yml | 81 | # - LLM_RESTOCK_MAX_CONTENT_CHARS=15000 | COMMENT |
| LOW | docker-compose.yml | 101 | COMMENT | |
| LOW | docker-compose.yml | 121 | # RECOMMENDED FOR FETCHING PAGES WITH CHROME, be sure to enable the "PLAYWRIGHT_DRIVER_URL" env variable in the mai | COMMENT |
| LOW | docker-compose.yml | 141 | # environment: | COMMENT |
| LOW | docs/api-spec.yaml | 801 | - null: Not decided yet / inherit default behavior | 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 | 41 | # By default, queries listed here will override any specified in a config file. | COMMENT |
| LOW | .github/workflows/test-only.yml | 61 | run: | | COMMENT |
| LOW | .github/actions/extract-memory-report/action.yml | 41 | # sed 's/.*Peak memory: //' | \ | 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 | # some_object = klass() | COMMENT |
| LOW | changedetectionio/html_tools.py | 361 | # - local-name(): //*[local-name()='title']/text() | COMMENT |
| LOW | changedetectionio/notification/handler.py | 381 | if _llm_change_summary and _override_diff: | COMMENT |
| LOW | …etectionio/tests/test_automatic_follow_ldjson_price.py | 181 | </body></html> | COMMENT |
| LOW | …etectionio/tests/test_automatic_follow_ldjson_price.py | 201 | # "offeredBy": { | 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 | # MEMORY MANAGEMENT: Why We Use Multiprocessing (Linux Only) | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 81 | # When a subprocess exits, the OS forcibly reclaims ALL memory including C-level | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 101 | # - The leak is specifically from lxml's document parsing, not the JSONPath queries | COMMENT |
| LOW | changedetectionio/processors/restock_diff/processor.py | 441 | # from ...html_tools import html_to_text | COMMENT |
| LOW | …ngedetectionio/static/styles/scss/parts/_sub_tabs.scss | 1 | // ── Vertical sub-tab layout ─────────────────────────────────────────────────── | COMMENT |
| LOW | changedetectionio/conditions/plugins/__init__.py | 1 | # Import plugins package to make them discoverable | COMMENT |
| LOW | changedetectionio/api/Watch.py | 281 | if content: | COMMENT |
| LOW | changedetectionio/blueprint/browser_steps/__init__.py | 1 | COMMENT | |
| LOW | changedetectionio/store/file_saving_datastore.py | 121 | try: | 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 | 62 | form.application.form.notification_format.choices.pop() | CODE |
| CRITICAL | changedetectionio/blueprint/settings/__init__.py | 70 | form.requests.form.proxy.choices.append(tuple((p, datastore.proxy_list[p]['label']))) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | changedetectionio/forms.py | 236 | CODE | |
| LOW | changedetectionio/content_fetchers/playwright.py | 250 | CODE | |
| LOW | changedetectionio/content_fetchers/puppeteer.py | 503 | CODE | |
| LOW | changedetectionio/content_fetchers/requests.py | 211 | CODE | |
| LOW | …angedetectionio/content_fetchers/webdriver_selenium.py | 63 | CODE | |
| LOW | changedetectionio/content_fetchers/base.py | 122 | CODE | |
| LOW | changedetectionio/tests/conftest.py | 321 | CODE | |
| LOW | changedetectionio/tests/util.py | 375 | 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 | 264 | CODE | |
| LOW | changedetectionio/model/Watch.py | 736 | CODE | |
| LOW | changedetectionio/model/Watch.py | 1306 | CODE | |
| LOW | changedetectionio/blueprint/ui/preview.py | 125 | CODE | |
| LOW | changedetectionio/blueprint/ui/__init__.py | 186 | CODE | |
| LOW | changedetectionio/blueprint/settings/__init__.py | 261 | CODE | |
| LOW | changedetectionio/blueprint/settings/__init__.py | 278 | CODE | |
| LOW | changedetectionio/blueprint/imports/__init__.py | 84 | CODE | |
| LOW | changedetectionio/blueprint/tags/__init__.py | 36 | CODE | |
| LOW | changedetectionio/blueprint/tags/__init__.py | 231 | CODE | |
| LOW | changedetectionio/blueprint/backups/__init__.py | 177 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | changedetectionio/worker_pool.py | 291 | """Bulletproof queue operation with comprehensive error handling""" | STRING |
| LOW | changedetectionio/html_tools.py | 465 | # Foreach <script json></script> blob.. just return the first that matches json_filter | COMMENT |
| LOW | changedetectionio/content_fetchers/requests.py | 198 | # 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 | 1139 | # DeepSeek-R1, Gemma 3, etc.) which emit chain-of-thought into | COMMENT |
| MEDIUM | …ctionio/processors/restock_diff/plugins/llm_restock.py | 246 | # models. Local reasoning models burn most of that on chain-of-thought before | 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 | 14 | __all__ = [ | CODE |
| LOW | changedetectionio/jinja2_custom/plugins/__init__.py | 6 | __all__ = ['regex_replace'] | 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 |