Universal SEO skill for Claude Code. 26 sub-skills + 19 sub-agents covering technical SEO, E-E-A-T, schema, GEO/AEO, agent readiness (Lighthouse Agentic Browsing, WebMCP, llms.txt), backlinks, local SEO, e-commerce, international SEO, Google APIs, and PDF/Excel reporting. 9 optional extensions for live SEO data.
This report summarizes scanner evidence for AgriciDaniel/claude-seo, a Python project with 18,686 GitHub stars. SynthScan examined 77,942 lines of code across 439 source files, recording 1378 pattern matches distributed across 20 syntactic categories. The legacy adjusted pattern signal is 29.7 (Elevated 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? 857 finding(s).
Are imports declared and package/API names verified? 113 finding(s).
Are wrappers, guards, and repeated structures necessary? 1121 finding(s).
Which changes need focused human review? 1378 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 1378 distinct pattern matches across 20 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 |
|---|---|---|---|---|
| MEDIUM⚡ | tests/test_metadata_template.py | 87 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 89 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 173 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 175 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 253 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 255 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 307 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_metadata_template.py | 309 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_metadata_template.py | 33 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_metadata_template.py | 35 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_metadata_template.py | 214 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_metadata_template.py | 216 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 33 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 35 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 125 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 127 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 207 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 209 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 362 | # --------------------------------------------------------------------------- | STRING |
| MEDIUM⚡ | tests/test_phase_j_executable.py | 364 | # --------------------------------------------------------------------------- | STRING |
| MEDIUM⚡ | tests/test_portability.py | 19 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_portability.py | 21 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_portability.py | 95 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_portability.py | 97 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_banana_cost_tracker.py | 60 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_banana_cost_tracker.py | 62 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_banana_cost_tracker.py | 145 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_banana_cost_tracker.py | 147 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_banana_cost_tracker.py | 202 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_banana_cost_tracker.py | 204 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_unlighthouse_run.py | 37 | # -------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_unlighthouse_run.py | 39 | # -------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_unlighthouse_run.py | 89 | # -------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_unlighthouse_run.py | 91 | # -------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_unlighthouse_run.py | 158 | # -------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_unlighthouse_run.py | 160 | # -------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_gbp_lint_and_polish.py | 23 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_gbp_lint_and_polish.py | 25 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_gbp_lint_and_polish.py | 80 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_gbp_lint_and_polish.py | 82 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_gbp_lint_and_polish.py | 100 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_gbp_lint_and_polish.py | 102 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_dataforseo_costs.py | 45 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_dataforseo_costs.py | 47 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_dataforseo_costs.py | 106 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_dataforseo_costs.py | 108 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_dataforseo_costs.py | 150 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_dataforseo_costs.py | 152 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 139 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 141 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 224 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 226 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 240 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 242 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 262 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 264 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 500 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 502 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 533 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_render_page.py | 535 | # --------------------------------------------------------------------------- | COMMENT |
| 147 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_agent_mcp_permissions.py | 16 | def test_dataforseo_agent_mirrors_allow_only_sanctioned_mcp_path(): | CODE |
| LOW | tests/test_agent_mcp_permissions.py | 25 | def test_dataforseo_agent_mirrors_fail_closed_without_mcp(): | CODE |
| LOW | tests/test_agent_mcp_permissions.py | 37 | def test_dataforseo_agent_bodies_stay_mirrored(): | CODE |
| LOW | tests/test_agent_mcp_permissions.py | 43 | def test_dataforseo_installers_use_matching_mcp_server_name(): | CODE |
| LOW⚡ | tests/test_metadata_template.py | 72 | def test_templated_pairs_are_flagged_high(title: str, description: str) -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 81 | def test_templated_pairs_report_the_matched_cta(title: str, description: str) -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 164 | def test_short_title_echo_is_not_flagged() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 178 | def test_brand_suffix_leaked_into_description() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 187 | def test_brand_named_first_in_description_is_not_a_leak() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 195 | def test_description_identical_to_title() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 203 | def test_title_echo_without_cta_is_medium_not_high() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 236 | def test_edge_cases_return_a_well_formed_result(title: str, description: str) -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 243 | def test_missing_metadata_is_reported_not_flagged() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 249 | def test_none_inputs_are_tolerated() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 271 | def test_site_wide_templating_is_high_risk() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 279 | def test_one_templated_page_is_not_a_site_pattern() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 286 | def test_clean_site_has_no_flags() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 293 | def test_shared_cta_tail_is_counted_across_pages() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 300 | def test_empty_site_does_not_divide_by_zero() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 319 | def test_cli_emits_valid_json() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 328 | def test_cli_fail_on_any_exits_nonzero() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 335 | def test_cli_without_input_returns_usage_error() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 341 | def test_cli_reads_a_pairs_file(tmp_path) -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 365 | def test_json_output_reports_heuristic_method() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 373 | def test_human_output_names_the_method_as_heuristic() -> None: | CODE |
| LOW⚡ | tests/test_metadata_template.py | 380 | def test_findings_do_not_claim_a_specific_spam_update_caused_or_targeted_this() -> None: | CODE |
| LOW | tests/test_metadata_template.py | 145 | def test_legitimate_pairs_are_not_flagged_templated(title: str, description: str) -> None: | CODE |
| LOW | tests/test_metadata_template.py | 152 | def test_cta_alone_is_not_enough_to_flag() -> None: | CODE |
| LOW | tests/test_metadata_template.py | 352 | def test_pairs_file_accepts_parse_html_meta_description_key(tmp_path) -> None: | CODE |
| LOW | tests/test_keywordseverywhere_api.py | 61 | def test_get_rank_posts_the_documented_bulk_request() -> None: | CODE |
| LOW⚡ | tests/test_keywordseverywhere_api.py | 83 | def test_get_rank_auth_error_maps_to_error_status() -> None: | CODE |
| LOW⚡ | tests/test_keywordseverywhere_api.py | 93 | def test_get_rank_rate_limit_maps_to_rate_limited_status() -> None: | CODE |
| LOW⚡ | tests/test_keywordseverywhere_api.py | 103 | def test_get_rank_html_error_page_is_not_echoed() -> None: | CODE |
| LOW | tests/test_keywordseverywhere_api.py | 116 | def test_get_rank_ssrf_block_surfaces_as_error_not_a_crash() -> None: | CODE |
| LOW | tests/test_keywordseverywhere_api.py | 140 | def test_upstream_error_body_never_echoes_the_key(monkeypatch): | CODE |
| LOW | tests/test_keywordseverywhere_api.py | 159 | def test_redirects_and_non_json_bodies_get_a_clear_error(status, message) -> None: | CODE |
| LOW | tests/test_keywordseverywhere_api.py | 169 | def test_post_goes_through_a_pinned_session_without_following_redirects() -> None: | CODE |
| LOW | tests/test_audit_instructions.py | 10 | def test_seo_audit_starts_with_render_page_auto() -> None: | CODE |
| LOW | tests/test_audit_instructions.py | 19 | def test_seo_audit_requires_persistent_artifacts() -> None: | CODE |
| LOW | tests/test_audit_instructions.py | 32 | def test_audit_agents_use_renderer_or_capture_script() -> None: | CODE |
| LOW | tests/test_audit_instructions.py | 45 | def test_audit_agents_document_output_dir_findings_contract() -> None: | CODE |
| LOW | tests/test_audit_instructions.py | 69 | def test_seo_audit_report_command_keeps_outputs_in_audit_dir() -> None: | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 38 | def test_discovery_url_for_normalizes_to_well_known(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 81 | def test_parse_profile_flags_a_flat_non_spec_profile(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 89 | def test_parse_profile_flags_missing_capability_fields(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 98 | def test_parse_profile_flags_missing_fields_and_unknown_capability(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 112 | def test_parse_profile_rejects_non_object_root(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 117 | def test_known_capabilities_cover_core_commerce_verbs(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 130 | def test_iptc_vocab_contains_required_merchant_center_value(): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 138 | def test_audit_reports_target_not_found(tmp_path): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 143 | def test_audit_reports_exiftool_unavailable(tmp_path, monkeypatch): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 152 | def test_inject_rejects_unknown_source_type(tmp_path): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 160 | def test_inject_reports_missing_exiftool(tmp_path, monkeypatch): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 169 | def test_inject_succeeds_when_subprocess_returns_zero(tmp_path, monkeypatch): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 212 | def test_analyze_html_counts_semantic_tags_and_widgets(): | CODE |
| LOW | tests/test_phase_j_executable.py | 55 | def test_parse_profile_rejects_malformed_json(): | CODE |
| LOW | tests/test_phase_j_executable.py | 61 | def test_parse_profile_valid_spec_profile(): | CODE |
| LOW | tests/test_phase_j_executable.py | 181 | def test_audit_classifies_files_via_mocked_exiftool(tmp_path, monkeypatch): | CODE |
| LOW⚡ | tests/test_phase_j_executable.py | 367 | def test_render_page_result_dict_includes_accessibility_tree_key(): | STRING |
| LOW | tests/test_phase_j_executable.py | 230 | def test_analyze_html_detects_unlabeled_inputs(): | STRING |
| 651 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | extensions/ahrefs/install.sh | 82 | except Exception: | CODE |
| LOW | extensions/dataforseo/install.sh | 151 | except Exception: | CODE |
| LOW | extensions/firecrawl/install.sh | 118 | except Exception: | CODE |
| LOW | extensions/banana/install.sh | 129 | except Exception: | CODE |
| LOW | extensions/banana/scripts/cost_tracker.py | 122 | except Exception: | CODE |
| MEDIUM | extensions/banana/scripts/cost_tracker.py | 163 | print(f"Error: Missing pricing config at {PRICING_PATH}.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/cost_tracker.py | 171 | print("Error: pricing.json must include checked_date and models.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/cost_tracker.py | 187 | print(f"Error: No pricing for model '{model}' in {PRICING_PATH}.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/cost_tracker.py | 196 | print(f"Error: No pricing for resolution '{resolution}' in {PRICING_PATH}.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/cost_tracker.py | 284 | print("Error: Pass --confirm to reset the cost ledger.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/cost_tracker.py | 334 | print(f"Error: {exc}", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/presets.py | 32 | print("Error: Preset name must contain only letters, numbers, hyphens, and underscores.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/presets.py | 47 | print(f"Error: Preset '{name}' not found.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/presets.py | 82 | print(f"Error: Preset '{args.name}' already exists. Use a different name.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/presets.py | 109 | print("Error: Pass --confirm to delete the preset.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/presets.py | 113 | print(f"Error: Preset '{args.name}' not found.", file=sys.stderr) | CODE |
| MEDIUM | extensions/banana/scripts/setup_mcp.py | 95 | print("Error: API key cannot be empty.") | CODE |
| MEDIUM | scripts/bing_webmaster.py | 25 | print("Error: requests library required. Install with: pip install requests") | CODE |
| MEDIUM | scripts/bing_webmaster.py | 34 | print("Error: backlinks_auth.py and google_auth.py required in scripts/", file=sys.stderr) | CODE |
| MEDIUM | scripts/bing_webmaster.py | 519 | print(f"Error: {result['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/bing_webmaster.py | 523 | print("Error: compare command requires a competitor URL", file=sys.stderr) | CODE |
| MEDIUM | scripts/bing_webmaster.py | 543 | print(f"Error: {result['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/bing_webmaster.py | 559 | print(f"Error: {result['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/bing_webmaster.py | 606 | print(f"Error: {result['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/sitemap_discovery.py | 281 | print(f"Error: {result['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/verify_release.py | 116 | print(f"Error: manifest not found: {args.manifest}", file=sys.stderr) | CODE |
| LOW | scripts/backlinks_auth.py | 109 | except Exception as exc: # best-effort hardening only; never fatal | CODE |
| MEDIUM⚡ | scripts/google_auth.py | 539 | print(f"Error exchanging authorization code: {e}", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_auth.py | 175 | print(f"Error loading service account: {e}", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_auth.py | 237 | print(f"Error reading OAuth client file: {e}", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_auth.py | 359 | print(f"Error refreshing OAuth token: {e}", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_auth.py | 415 | print("Error: google-auth required. Install with: pip install google-auth", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_auth.py | 438 | print("Error: Could not load OAuth client credentials.", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_auth.py | 611 | print(f"Error building {api_name} service: {e}", file=sys.stderr) | CODE |
| LOW⚡ | scripts/google_auth.py | 529 | except Exception as e: | CODE |
| LOW⚡ | scripts/google_auth.py | 538 | except Exception as e: | CODE |
| LOW | scripts/google_auth.py | 174 | except Exception as e: | CODE |
| LOW | scripts/google_auth.py | 225 | except Exception as e: | CODE |
| LOW | scripts/google_auth.py | 329 | except Exception: | CODE |
| LOW | scripts/google_auth.py | 358 | except Exception as e: | CODE |
| LOW | scripts/google_auth.py | 475 | except Exception: | CODE |
| LOW | scripts/google_auth.py | 610 | except Exception as e: | CODE |
| MEDIUM | scripts/google_auth.py | 901 | print("Error: --creds is required with --auth", file=sys.stderr) | STRING |
| MEDIUM | scripts/google_auth.py | 908 | print("Error: --creds and --code are required with --exchange", file=sys.stderr) | STRING |
| MEDIUM | scripts/matomo_auth.py | 30 | print("Error: requests library required. Install with: pip install requests", | CODE |
| LOW | scripts/matomo_auth.py | 101 | except Exception as exc: # best-effort hardening only; never fatal | CODE |
| LOW | scripts/agentic_check.py | 163 | except Exception as exc: # network errors are findings, not crashes | CODE |
| MEDIUM⚡ | scripts/drift_report.py | 346 | print(f"Error: File not found: {args.file}", file=sys.stderr) | CODE |
| MEDIUM⚡ | scripts/drift_report.py | 351 | print("Error: Provide a JSON file path or use --stdin", file=sys.stderr) | CODE |
| MEDIUM⚡ | scripts/drift_report.py | 357 | print(f"Error: Invalid JSON: {e}", file=sys.stderr) | CODE |
| MEDIUM⚡ | scripts/drift_report.py | 361 | print(f"Error: Comparison has error: {comparison['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/iptc_ai_label.py | 205 | print(f"Error: {report['summary']['error']}", file=sys.stderr) | CODE |
| MEDIUM | scripts/iptc_ai_label.py | 219 | print(f"Error: {out['error']}", file=sys.stderr) | CODE |
| MEDIUM⚡ | scripts/google_report.py | 2683 | print(f"Error reading data file: {e}", file=sys.stderr) | CODE |
| MEDIUM⚡ | scripts/google_report.py | 2689 | print(f"Error parsing stdin JSON: {e}", file=sys.stderr) | CODE |
| MEDIUM⚡ | scripts/google_report.py | 2692 | print("Error: Provide --data file or pipe JSON via stdin.", file=sys.stderr) | CODE |
| MEDIUM | scripts/google_report.py | 2704 | print(f"Error: {result['error']}", file=sys.stderr) | CODE |
| LOW | scripts/google_report.py | 2408 | except Exception as e: | CODE |
| MEDIUM | scripts/gbp_deprecation_lint.py | 115 | print(f"Error: url_safety: {exc}", file=sys.stderr) | CODE |
| LOW | scripts/capture_screenshot.py | 152 | except Exception as e: | CODE |
| 107 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | extensions/banana/scripts/setup_mcp.py | 55 | except OSError: | CODE |
| HIGH | hooks/validate-schema.py | 281 | except (OSError, ValueError): | CODE |
| HIGH | scripts/backlinks_auth.py | 141 | except OSError: | CODE |
| HIGH | scripts/google_auth.py | 247 | except OSError: | CODE |
| HIGH | scripts/google_auth.py | 295 | except OSError: | CODE |
| HIGH | scripts/google_auth.py | 475 | except Exception: | CODE |
| HIGH | scripts/google_auth.py | 742 | except (json.JSONDecodeError, IOError): | CODE |
| HIGH | scripts/content_quality.py | 308 | except (ValueError, OSError): | CODE |
| HIGH | scripts/matomo_auth.py | 271 | except ValueError: | CODE |
| HIGH | scripts/matomo_auth.py | 136 | except OSError: | CODE |
| HIGH | scripts/matomo_auth.py | 147 | except OSError: | CODE |
| HIGH | scripts/google_report.py | 2430 | except OSError: | CODE |
| HIGH | scripts/url_safety.py | 999 | except Exception: | CODE |
| HIGH | scripts/commoncrawl_graph.py | 223 | except requests.exceptions.Timeout: | CODE |
| HIGH | scripts/commoncrawl_graph.py | 225 | except MemoryError: | CODE |
| HIGH | scripts/commoncrawl_graph.py | 151 | except (json.JSONDecodeError, IOError): | CODE |
| HIGH | scripts/commoncrawl_graph.py | 320 | except Exception: | CODE |
| HIGH | scripts/parse_html.py | 237 | except (json.JSONDecodeError, TypeError): | CODE |
| HIGH | scripts/analyze_visual.py | 133 | except Exception: | CODE |
| HIGH | scripts/analyze_visual.py | 151 | except Exception: | CODE |
| HIGH | scripts/drift_baseline.py | 205 | except OSError: | CODE |
| HIGH | scripts/sync_flow.py | 347 | except ValueError: | CODE |
| HIGH | scripts/sync_flow.py | 248 | except OSError: | CODE |
| HIGH | scripts/runtime.py | 85 | except OSError: | CODE |
| HIGH | scripts/runtime.py | 222 | except RuntimeError: | CODE |
| HIGH | scripts/runtime.py | 78 | except (OSError, ValueError): | CODE |
| HIGH | scripts/youtube_search.py | 225 | except Exception: | CODE |
| HIGH | scripts/moz_api.py | 93 | except (IOError, ValueError): | CODE |
| HIGH | scripts/moz_api.py | 78 | except (ImportError, OSError): | CODE |
| HIGH | scripts/render_page.py | 394 | except Exception: | CODE |
| HIGH | scripts/render_page.py | 400 | except Exception: | CODE |
| HIGH | scripts/render_page.py | 592 | except Exception: | CODE |
| HIGH | scripts/render_page.py | 598 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_metadata_template.py | 18 | CODE | |
| LOW | tests/test_keywordseverywhere_api.py | 12 | CODE | |
| LOW | tests/test_audit_instructions.py | 3 | CODE | |
| LOW | tests/test_phase_j_executable.py | 13 | CODE | |
| LOW | tests/test_portability.py | 7 | CODE | |
| LOW | tests/test_dataforseo_tool_names.py | 11 | CODE | |
| LOW | tests/test_canonical_facts.py | 8 | CODE | |
| LOW | tests/test_fetch_page_decoding.py | 3 | CODE | |
| LOW | tests/test_nlp_analyze.py | 3 | CODE | |
| LOW | tests/test_gsc_pagination.py | 3 | CODE | |
| LOW | tests/test_schema_hook_redos.py | 3 | CODE | |
| LOW | tests/test_banana_cost_tracker.py | 15 | CODE | |
| LOW | tests/test_banana_api_key_safety.py | 3 | CODE | |
| LOW | tests/test_pagespeed_null_category_score.py | 8 | CODE | |
| LOW | tests/test_google_gcloud_adc.py | 8 | CODE | |
| LOW | tests/test_extension_installer_injection.py | 11 | CODE | |
| LOW | tests/test_drift_portability.py | 3 | CODE | |
| LOW | tests/test_unlighthouse_run.py | 24 | CODE | |
| LOW | tests/test_banana_setup_mcp_atomic_write.py | 9 | CODE | |
| LOW | tests/test_gbp_lint_and_polish.py | 8 | CODE | |
| LOW | tests/test_powershell_ascii.py | 9 | CODE | |
| LOW | tests/test_gsc_totals_aggregate.py | 6 | CODE | |
| LOW | tests/test_file_size_limits.py | 7 | CODE | |
| LOW | tests/test_runtime.py | 3 | CODE | |
| LOW | tests/test_validate_backlink_report.py | 3 | CODE | |
| LOW | tests/test_domain_history.py | 14 | CODE | |
| LOW | tests/test_agentic.py | 13 | CODE | |
| LOW | tests/test_backlinks_auth_hardening.py | 11 | CODE | |
| LOW | tests/test_banana_key_masking.py | 8 | CODE | |
| LOW | tests/test_audit_agent_turn_budget.py | 15 | CODE | |
| LOW | tests/test_cross_platform_hooks.py | 3 | CODE | |
| LOW | tests/test_schema_hook_detection.py | 14 | CODE | |
| LOW | tests/test_dataforseo_costs.py | 14 | CODE | |
| LOW | tests/test_render_page.py | 19 | CODE | |
| LOW | tests/test_technical_depth.py | 15 | CODE | |
| LOW | tests/test_no_em_dash.py | 20 | CODE | |
| LOW | tests/test_sitemap_discovery.py | 3 | CODE | |
| LOW | tests/test_google_api_key_safety.py | 7 | CODE | |
| LOW | tests/test_google_report_full_audit.py | 3 | CODE | |
| LOW | tests/test_moz_api.py | 3 | CODE | |
| LOW | tests/test_schema_hook_policy.py | 8 | CODE | |
| LOW | tests/test_hostile_inputs.py | 7 | CODE | |
| LOW | tests/test_content_quality.py | 14 | CODE | |
| LOW | tests/test_pyproject_metadata.py | 3 | CODE | |
| LOW | tests/test_matomo_report.py | 16 | CODE | |
| LOW | tests/test_commoncrawl_graph.py | 14 | CODE | |
| LOW | tests/test_bing_webmaster.py | 3 | CODE | |
| LOW | tests/test_contributors.py | 3 | CODE | |
| LOW | tests/test_schema_v2.py | 12 | CODE | |
| LOW | tests/test_backlink_score_gate.py | 7 | CODE | |
| LOW | tests/test_url_safety.py | 12 | CODE | |
| LOW | tests/test_hosted_plugin_layout.py | 16 | CODE | |
| LOW | tests/test_ai_crawler_claims.py | 3 | CODE | |
| LOW | tests/test_gsc_query.py | 3 | CODE | |
| LOW | tests/test_parasite_risk_and_extensions.py | 8 | CODE | |
| LOW | scripts/sitemap_discovery.py | 9 | CODE | |
| LOW | scripts/verify_release.py | 30 | CODE | |
| LOW | scripts/backlinks_auth.py | 30 | CODE | |
| LOW | scripts/content_quality.py | 54 | CODE | |
| LOW | scripts/schema_generate.py | 47 | CODE | |
| 26 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_dataforseo_tool_names.py | 37 | CODE | |
| LOW | tests/test_runtime.py | 246 | CODE | |
| LOW | tests/test_agentic.py | 512 | CODE | |
| LOW | extensions/banana/scripts/batch.py | 35 | CODE | |
| LOW | hooks/validate-schema.py | 159 | CODE | |
| LOW | hooks/validate-schema.py | 191 | CODE | |
| LOW | hooks/validate-schema.py | 264 | CODE | |
| LOW | scripts/bing_webmaster.py | 190 | CODE | |
| LOW | scripts/bing_webmaster.py | 383 | CODE | |
| LOW | scripts/bing_webmaster.py | 474 | CODE | |
| LOW | scripts/sitemap_discovery.py | 74 | CODE | |
| LOW | scripts/sitemap_discovery.py | 183 | CODE | |
| LOW | scripts/sitemap_discovery.py | 272 | CODE | |
| LOW | scripts/backlinks_auth.py | 153 | CODE | |
| LOW | scripts/backlinks_auth.py | 205 | CODE | |
| LOW | scripts/backlinks_auth.py | 515 | CODE | |
| LOW | scripts/google_auth.py | 363 | CODE | |
| LOW | scripts/google_auth.py | 615 | CODE | |
| LOW | scripts/google_auth.py | 710 | CODE | |
| LOW | scripts/google_auth.py | 852 | CODE | |
| LOW | scripts/matomo_auth.py | 166 | CODE | |
| LOW | scripts/schema_generate.py | 246 | CODE | |
| LOW | scripts/agentic_check.py | 206 | CODE | |
| LOW | scripts/agentic_check.py | 643 | CODE | |
| LOW | scripts/agentic_check.py | 753 | CODE | |
| LOW | scripts/google_report.py | 1091 | CODE | |
| LOW | scripts/google_report.py | 2066 | CODE | |
| LOW | scripts/google_report.py | 2472 | CODE | |
| LOW | scripts/dataforseo_normalize.py | 87 | CODE | |
| LOW | scripts/ga4_report.py | 396 | CODE | |
| LOW | scripts/url_safety.py | 649 | CODE | |
| LOW | scripts/url_safety.py | 690 | CODE | |
| LOW | scripts/schema_ecommerce_validate.py | 112 | CODE | |
| LOW | scripts/commoncrawl_graph.py | 164 | CODE | |
| LOW | scripts/commoncrawl_graph.py | 231 | CODE | |
| LOW | scripts/ucp_check.py | 79 | CODE | |
| LOW | scripts/parse_html.py | 91 | CODE | |
| LOW | scripts/gsc_query.py | 428 | CODE | |
| LOW | scripts/indexing_notify.py | 65 | CODE | |
| LOW | scripts/indexing_notify.py | 248 | CODE | |
| LOW | scripts/analyze_visual.py | 47 | CODE | |
| LOW | scripts/parasite_risk.py | 118 | CODE | |
| LOW | scripts/crux_history.py | 54 | CODE | |
| LOW | scripts/sync_flow.py | 273 | CODE | |
| LOW | scripts/pagespeed_check.py | 80 | CODE | |
| LOW | scripts/pagespeed_check.py | 318 | CODE | |
| LOW | scripts/pagespeed_check.py | 493 | CODE | |
| LOW | scripts/runtime.py | 273 | CODE | |
| LOW | scripts/agent_ux_check.py | 131 | CODE | |
| LOW | scripts/matomo_report.py | 564 | CODE | |
| LOW | scripts/matomo_report.py | 650 | CODE | |
| LOW | scripts/lighthouse_agentic.py | 202 | CODE | |
| LOW | scripts/seo_updates.py | 100 | CODE | |
| LOW | scripts/lcp_subparts.py | 88 | CODE | |
| LOW | scripts/agentic_fix.py | 325 | CODE | |
| LOW | scripts/keyword_planner.py | 48 | CODE | |
| LOW | scripts/keyword_planner.py | 246 | CODE | |
| LOW | scripts/youtube_search.py | 288 | CODE | |
| LOW | scripts/validate_backlink_report.py | 272 | CODE | |
| LOW | scripts/domain_history.py | 111 | CODE | |
| 10 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | agents/seo-backlinks.md | 89 | ### Step 1: Automated validation | COMMENT |
| LOW | agents/seo-backlinks.md | 97 | ### Step 2: Manual checks (not automatable) | COMMENT |
| LOW⚡ | scripts/drift_baseline.py | 153 | # Step 1: Fetch the page via fetch_page.py | STRING |
| LOW | scripts/drift_baseline.py | 188 | # Step 2: Parse the HTML via parse_html.py | STRING |
| LOW⚡ | scripts/render_page.py | 582 | # Step 2: content extraction (works on either raw or rendered HTML). | COMMENT |
| LOW | scripts/render_page.py | 459 | # Step 1: raw fetch (always; needed for SPA detection and as a baseline). | COMMENT |
| LOW | scripts/verify_backlinks.py | 130 | # Step 1: HEAD check | COMMENT |
| LOW | scripts/verify_backlinks.py | 153 | # Step 2: Full GET + parse | COMMENT |
| LOW | scripts/verify_backlinks.py | 170 | # Step 3: Parse HTML and find target link | COMMENT |
| LOW | skills/seo-google/references/auth-setup.md | 13 | ## Step 1: Create a Google Cloud Project | COMMENT |
| LOW | skills/seo-google/references/auth-setup.md | 20 | ## Step 2: Enable APIs | COMMENT |
| LOW | skills/seo-google/references/auth-setup.md | 33 | ## Step 3: Create an API Key | COMMENT |
| LOW | skills/seo-google/references/auth-setup.md | 40 | ## Step 4: Create a Service Account | COMMENT |
| LOW⚡ | skills/seo-google/references/auth-setup.md | 64 | ## Step 5: Grant Search Console Access | COMMENT |
| LOW⚡ | skills/seo-google/references/auth-setup.md | 74 | ## Step 6: Grant GA4 Access | COMMENT |
| LOW⚡ | skills/seo-google/references/auth-setup.md | 82 | ## Step 7: Create Config File | COMMENT |
| LOW | skills/seo-google/references/auth-setup.md | 106 | ## Step 8: Verify Setup | COMMENT |
| LOW | skills/seo-cluster/SKILL.md | 41 | ### Step 1: Seed Keyword Expansion | COMMENT |
| LOW | skills/seo-cluster/SKILL.md | 55 | ### Step 2: SERP Overlap Clustering | COMMENT |
| LOW | skills/seo-cluster/SKILL.md | 83 | ### Step 3: Intent Classification | COMMENT |
| LOW | skills/seo-cluster/SKILL.md | 98 | ### Step 4: Hub-and-Spoke Architecture | COMMENT |
| LOW | skills/seo-cluster/SKILL.md | 127 | ### Step 5: Internal Link Matrix | COMMENT |
| LOW | skills/seo-cluster/SKILL.md | 154 | ### Step 6: Interactive Cluster Map | COMMENT |
| LOW⚡ | …lls/seo-cluster/references/serp-overlap-methodology.md | 12 | ### Step 1: Collect SERP Data | COMMENT |
| LOW⚡ | …lls/seo-cluster/references/serp-overlap-methodology.md | 20 | ### Step 2: Pairwise Comparison | COMMENT |
| LOW⚡ | …lls/seo-cluster/references/serp-overlap-methodology.md | 27 | ### Step 3: Apply Thresholds | COMMENT |
| LOW⚡ | …lls/seo-cluster/references/serp-overlap-methodology.md | 36 | ### Step 4: Handle Ambiguous Scores (3-4 Range) | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 41 | ### Step 1: Target Acquisition | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 49 | ### Step 2: SERP Backwards Analysis | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 74 | ### Step 3: Page-Type Mismatch Detection | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 95 | ### Step 4: User Story Derivation | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 117 | ### Step 5: Gap Analysis | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 133 | ### Step 6: Persona-Based Scoring | COMMENT |
| LOW | skills/seo-sxo/SKILL.md | 149 | ### Step 7: Wireframe Generation (Optional) | COMMENT |
| LOW | …rompts/optimize/step-1-the-chatgpt-discovery-prompt.md | 11 | # Step 1: The ChatGPT Discovery Prompt | COMMENT |
| LOW | …pts/optimize/step-2-the-follow-up-qualifying-prompt.md | 11 | # Step 2: The Follow-Up Qualifying Prompt | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | README.md | 20 | - **AI-search first.** Aligned with [Google's AI Optimization Guide](https://developers.google.com/search/docs/fundament | CODE |
| HIGH | README.md | 448 | Most SEO tools treat AI search as a separate optimization discipline. Claude SEO follows [Google's own position](https:/ | CODE |
| HIGH⚡ | tests/test_phase_j_executable.py | 131 | # Google Merchant Center requires this exact label on AI-generated images. | COMMENT |
| HIGH⚡ | scripts/drift_report.py | 308 | Generated by Claude SEO Drift Monitor | {report_time} | CODE |
| HIGH | scripts/google_report.py | 2055 | f' Report generated by Claude SEO (Google SEO Intelligence Skill), ' | CODE |
| HIGH | scripts/agentic_fix.py | 286 | // Draft generated by claude-seo. WebMCP is a W3C Community Group draft. | COMMENT |
| HIGH | skills/seo-cluster/templates/cluster-map.html | 315 | <footer>Generated by Claude SEO</footer> | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | scripts/capture_screenshot.py | 33 | "pip install playwright && playwright install chromium" | CODE |
| HIGH | scripts/analyze_visual.py | 19 | print("Error: playwright required. Install with: pip install playwright && playwright install chromium") | CODE |
| HIGH | scripts/agentic_fix.py | 289 | if (mc?.registerTool && form) {{ | CODE |
| HIGH | scripts/domain_history.py | 44 | "years_registered": float or null, | STRING |
| HIGH | scripts/domain_history.py | 45 | "topical_shift": true|false|null, | STRING |
| HIGH | scripts/render_page.py | 300 | "(document.body && document.body.innerText || '').trim().length," | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_render_page.py | 73 | + ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " * 5) | CODE |
| LOW | tests/test_render_page.py | 73 | + ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " * 5) | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 47 | result = bing.get_link_counts("https://site.test/", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 57 | result = bing.get_link_counts("https://site.test/", "placeholder", max_pages=1) | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 68 | result = bing.get_link_counts("https://site.test/", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 76 | result = bing.get_link_counts("https://site.test/", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 91 | result = bing.get_link_details("https://site.test/", "placeholder", max_detail_pages=2) | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 113 | result = bing.get_link_details("https://site.test/", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 126 | result = bing.get_link_details("https://site.test/", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 133 | result = bing.get_link_details("https://site.test/", "placeholder", page=-1) | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 147 | result = bing.get_link_details("https://site.test/", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 155 | result = bing.compare_links("https://a.test", "https://b.test", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 167 | result = bing.compare_links("https://a.test", "https://b.test", "placeholder") | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 181 | result = bing._bing_request("GetLinkCounts", "placeholder", params) | CODE |
| LOW⚡ | tests/test_bing_webmaster.py | 187 | assert sent_params == {"siteUrl": "https://site.test/", "page": 0, "apikey": "placeholder"} | CODE |
| LOW | hooks/validate-schema.py | 319 | critical_keywords = ["placeholder", "deprecated", "retired"] | CODE |
| LOW | scripts/agentic_fix.py | 206 | label = label or el.get("aria-label") or el.get("placeholder") or name | CODE |
| LOW | skills/seo-plan/assets/local-service.md | 76 | "streetAddress": "123 Main St", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | README.md | 20 | - **AI-search first.** Aligned with [Google's AI Optimization Guide](https://developers.google.com/search/docs/fundament | CODE |
| MEDIUM | docs/COMMANDS.md | 180 | ### `/seo agentic [audit|fix|lighthouse|refresh] <url>` | COMMENT |
| MEDIUM | extensions/ahrefs/skills/seo-ahrefs/SKILL.md | 45 | ## Cost guardrails | COMMENT |
| MEDIUM | extensions/seranking/skills/seo-seranking/SKILL.md | 42 | ## Cost guardrails | COMMENT |
| MEDIUM | …/seo-agentic/references/lighthouse-agentic-category.md | 56 | ### ARD catalog discovery order (gatherer `agentic/ard.js`) | COMMENT |
| MEDIUM | skills/seo/references/thinking-framework.md | 121 | ### 6. CONNECT: system orchestration | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | docs/MCP-INTEGRATION.md | 57 | "PAGESPEED_API_KEY": "your-api-key" | CODE |
| HIGH | extensions/firecrawl/docs/FIRECRAWL-SETUP.md | 31 | "FIRECRAWL_API_KEY": "fc-your-api-key-here" | CODE |
| HIGH | extensions/banana/docs/BANANA-SETUP.md | 25 | "GOOGLE_AI_API_KEY": "your-api-key-here" | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | extensions/dataforseo/install.sh | 85 | # Check if running from repo or standalone | COMMENT |
| LOW | extensions/firecrawl/install.sh | 67 | # Check if running from repo or standalone | COMMENT |
| LOW | extensions/banana/uninstall.sh | 16 | # Check if standalone banana skill still exists | COMMENT |
| LOW | extensions/banana/install.sh | 53 | # Check if running from repo or standalone | COMMENT |
| LOW | extensions/banana/install.sh | 64 | # Check if nanobanana-mcp is already configured | COMMENT |
| LOW | scripts/google_auth.py | 386 | # Check if token needs refresh | COMMENT |
| LOW | scripts/validate_backlink_report.py | 42 | # Check if it's a @graph wrapper that wasn't flattened | COMMENT |
| LOW | scripts/validate_backlink_report.py | 130 | # Check if ALL H1s are suspicious (likely no real heading) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | scripts/drift_baseline.py | 153 | # Step 1: Fetch the page via fetch_page.py | STRING |
| LOW | scripts/drift_baseline.py | 188 | # Step 2: Parse the HTML via parse_html.py | STRING |
| LOW⚡ | scripts/render_page.py | 582 | # Step 2: content extraction (works on either raw or rendered HTML). | COMMENT |
| LOW | scripts/render_page.py | 459 | # Step 1: raw fetch (always; needed for SPA detection and as a baseline). | COMMENT |
| LOW | scripts/verify_backlinks.py | 130 | # Step 1: HEAD check | COMMENT |
| LOW | scripts/verify_backlinks.py | 153 | # Step 2: Full GET + parse | COMMENT |
| LOW | scripts/verify_backlinks.py | 170 | # Step 3: Parse HTML and find target link | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | uninstall.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | hooks/validate-schema.py | 61 | # blocks carrying a CSP ``nonce``, an ``id`` or ``data-*`` attributes, or an | COMMENT |
| LOW | scripts/url_safety.py | 121 | # allowlist of "looks like a numeric address" forms we want to canonicalize | COMMENT |
| LOW | scripts/url_safety.py | 221 | or (ip.version == 4 and ip in _SHARED_ADDRESS_SPACE) | COMMENT |
| LOW | scripts/url_safety.py | 241 | # | COMMENT |
| LOW | scripts/url_safety.py | 761 | ) | COMMENT |
| LOW | scripts/fetch_page.py | 41 | from url_safety import DEFAULT_USER_AGENT as DEFAULT_USER_AGENT # noqa: E402,F401 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | tests/test_phase_j_executable.py | 144 | # Create a real file so we get past the target-exists check. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | tests/test_content_humanize.py | 60 | # A zero-width space inside "delve" must not defeat the \b pattern. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | scripts/content_quality.py | 126 | "it's worth noting that", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/matomo_auth.py | 453 | CODE | |
| LOW | scripts/drift_baseline.py | 401 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/url_safety.py | 105 | __all__ = [ | CODE |