Skip to content

feat(static): classify suspicious URLs in configuration files - #134

Merged
vineethsai7 merged 15 commits into
cisco-ai-defense:mainfrom
federicoroncallo-hub:feat/pr3-config-url-classifier
Aug 3, 2026
Merged

feat(static): classify suspicious URLs in configuration files#134
vineethsai7 merged 15 commits into
cisco-ai-defense:mainfrom
federicoroncallo-hub:feat/pr3-config-url-classifier

Conversation

@federicoroncallo-hub

@federicoroncallo-hub federicoroncallo-hub commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Suspicious/tunnel URLs were only classified when they appeared as Python string literals (via ContextExtractor). Config files (config.yaml, settings.toml, …) are typed other and never reached that path, so a tunnel/exfil endpoint hidden in a config value went unnoticed.

This PR:

  • Extracts the suspicious/legitimate domain lists and URL-classification logic out of ContextExtractor into a shared core/static_analysis/url_classifier.py (classify_url, extract_urls) — a single source of truth reused by every analyzer.
  • Adds _scan_config_files() to the static analyzer, emitting CONFIG_SUSPICIOUS_URL (HIGH) for suspicious URLs found in config files. URLs are extracted from the raw file text, so endpoints in comments are covered too.
  • Registers CONFIG_SUSPICIOUS_URL in data/packs/core/pack.yaml; updates static/behavioral analyzer docs; adds an eval sample (config-tunnel-exfil).

Stacked on #132. This branch is based on feat/pr1-tunnel-domains, so the diff currently includes that PR's commits (the updated tunnel-domain lists). Once #132 merges, this diff will show only the config-scanning changes. Please review #132 first.

Test plan

  • tests/static_analysis/test_config_url_scanning.py — classifier unit tests, refactor-safety tests (ContextExtractor behavior unchanged), and config-format integration tests (YAML/JSON/TOML).
  • uv run pytest tests/ passes.
  • uv run pre-commit run --all-files passes.
  • uv run python evals/runners/benchmark_runner.py — 100% precision/recall, no regression.

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added detection of suspicious or tunnel URLs in supported configuration files.
    • Added a high-severity finding with redacted URL details when detected.
    • Improved URL classification across code and configuration scanning.
  • Documentation

    • Updated analyzer documentation to describe configuration URL scanning and shared URL detection.
  • Tests

    • Added coverage for URL classification, configuration formats, malformed files, filtering, and sensitive-data redaction.
    • Added an evaluation scenario for unsafe OAuth tunnel configuration.

federicoroncallo-hub and others added 3 commits July 2, 2026 11:22
…et/localtunnel.me

ngrok migrated off ngrok.io to ngrok-free.dev / ngrok.app, so exfil to a
current ngrok endpoint slipped past the suspicious-domain checks. Add the
modern ngrok domains plus bore.pub, serveo.net and localtunnel.me to:

- ContextExtractor.SUSPICIOUS_DOMAINS (Python string-literal URL classification)
- tool_chaining_abuse_generic.yara / command_injection_generic.yara exfil dests
- cross_skill_scanner exfil pattern list

Add regression tests for the new domains (YARA true-positives + ContextExtractor).

Co-authored-by: Cursor <cursoragent@cursor.com>
The suspicious/legitimate domain lists and matching logic previously lived
inside ContextExtractor and only ran over Python AST string literals, so a
tunnel/proxy endpoint hidden in a config value (e.g. base_url in config.yaml)
was never classified.

Refactor (behavior-preserving): extract SUSPICIOUS_DOMAINS/LEGITIMATE_DOMAINS
and the classification into skill_scanner/core/static_analysis/url_classifier.py
(classify_url + extract_urls). ContextExtractor imports from it and keeps the
lists as class attributes for backward compatibility; existing suspicious-URL
behavior is unchanged (covered by refactor-safety tests).

New pass: StaticAnalyzer._scan_config_files() parses config.yaml/.yml/.json,
settings.*, and *.toml (regex fallback on parse failure), runs each URL through
the shared classifier, and emits CONFIG_SUSPICIOUS_URL (HIGH). Registered in
the core pack.yaml.

Docs updated (static-analyzer, behavioral-analyzer). Adds unit tests plus a
labeled config-routed exfil eval sample; benchmark stays at 100% P/R.

Co-authored-by: Cursor <cursoragent@cursor.com>
Collapse the structured YAML/JSON/TOML parse-and-walk in config URL
scanning down to a single raw-text extract_urls() pass. The raw scan is
simpler, drops the json/yaml/tomllib imports and the _iter_string_values
recursion, and additionally catches suspicious URLs hidden in config
comments. classify_url() still only flags known tunnel/exfil domains, so
false-positive risk stays low.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: adbceadc-232b-4d94-8ef8-52c72b6fe085

📥 Commits

Reviewing files that changed from the base of the PR and between 6994a42 and 1f8c3cb.

📒 Files selected for processing (2)
  • skill_scanner/core/static_analysis/context_extractor.py
  • skill_scanner/core/static_analysis/url_classifier.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • skill_scanner/core/static_analysis/context_extractor.py

📝 Walkthrough

Walkthrough

The change adds shared URL classification and configuration-file URL scanning to static analysis. It registers CONFIG_SUSPICIOUS_URL, redacts sensitive URL components, updates ContextExtractor, and adds evaluation fixtures, tests, and documentation.

Changes

Config URL scanning and tunnel domain detection

Layer / File(s) Summary
Shared URL classifier
skill_scanner/core/static_analysis/url_classifier.py
Adds shared suspicious and legitimate domain lists, URL extraction, hostname matching, classification, de-duplication, and punctuation handling.
ContextExtractor classifier integration
skill_scanner/core/static_analysis/context_extractor.py
Uses the shared classifier and preserves class-level domain aliases.
StaticAnalyzer config URL scanning
skill_scanner/core/analyzers/static.py, skill_scanner/data/packs/core/pack.yaml
Scans recognized configuration files, emits high-severity CONFIG_SUSPICIOUS_URL findings, reports line numbers, and redacts credentials, query values, and fragments.
Config-tunnel evaluation fixture
evals/skills/data-exfiltration/config-tunnel-exfil/*
Adds a calendar-sync-helper skill, tunnel URL configuration, and expected high-severity detection output.
Classifier and detection tests
tests/static_analysis/test_config_url_scanning.py
Tests URL classification, extraction, compatibility, configuration formats, filtering, finding metadata, and redaction.
Analyzer documentation
docs/architecture/analyzers/behavioral-analyzer.md, docs/architecture/analyzers/static-analyzer.md
Documents shared URL classification and the configuration-file scanning pass.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StaticAnalyzer
  participant ConfigFile
  participant url_classifier
  participant Finding
  StaticAnalyzer->>ConfigFile: read recognized configuration content
  StaticAnalyzer->>url_classifier: extract and classify URLs
  url_classifier-->>StaticAnalyzer: return URL classifications
  StaticAnalyzer->>Finding: emit redacted CONFIG_SUSPICIOUS_URL finding
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: detecting suspicious URLs in configuration files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skill_scanner/core/analyzers/static.py`:
- Around line 627-638: The finding construction in static.py is copying the raw
config URL into multiple report fields, which can leak credentials or other
sensitive URL parts. Update the suspicious/tunnel URL finding path to use a
redaction helper near _find_line_number (for example, _redact_url_for_finding)
that preserves scheme/host/path but strips userinfo and replaces query/fragment
with placeholders. Apply the redacted value consistently wherever the URL is
assigned to snippet, metadata["url"], or any other finding payload in this
analyzer.

In `@skill_scanner/core/static_analysis/url_classifier.py`:
- Around line 145-158: The URL classifier in classify_url is matching
LEGITIMATE_DOMAINS and SUSPICIOUS_DOMAINS against the entire URL string, which
allows path/query substrings to override the host. Update classify_url to parse
the URL, normalize the hostname, and make decisions using exact host or
subdomain boundary checks against the hostname only. Keep the existing
precedence behavior, but apply it after hostname-based matching rather than raw
substring checks, and use the existing URL_RE/_URL_RE helpers and domain lists
to locate the logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c59b18e-dcf2-4aa3-b91d-21fa3c5ee68a

📥 Commits

Reviewing files that changed from the base of the PR and between 41fec4a and 4ebaaf1.

📒 Files selected for processing (15)
  • docs/architecture/analyzers/behavioral-analyzer.md
  • docs/architecture/analyzers/static-analyzer.md
  • evals/skills/data-exfiltration/config-tunnel-exfil/SKILL.md
  • evals/skills/data-exfiltration/config-tunnel-exfil/_expected.json
  • evals/skills/data-exfiltration/config-tunnel-exfil/config.yaml
  • skill_scanner/core/analyzers/cross_skill_scanner.py
  • skill_scanner/core/analyzers/static.py
  • skill_scanner/core/static_analysis/context_extractor.py
  • skill_scanner/core/static_analysis/url_classifier.py
  • skill_scanner/data/packs/core/pack.yaml
  • skill_scanner/data/packs/core/yara/command_injection_generic.yara
  • skill_scanner/data/packs/core/yara/tool_chaining_abuse_generic.yara
  • tests/static_analysis/test_config_url_scanning.py
  • tests/static_analysis/test_suspicious_url_domains.py
  • tests/test_yara_true_positives.py

Comment thread skill_scanner/core/analyzers/static.py Outdated
Comment thread skill_scanner/core/static_analysis/url_classifier.py Outdated
gyrospectre and others added 9 commits July 24, 2026 08:47
ProviderConfig.validate() required a truthy credential for every provider
except Bedrock and Ollama, and the only credential source it checked for
Vertex was GOOGLE_APPLICATION_CREDENTIALS. This blocked ambient auth via
a GCE/Cloud Run attached service account or Workload Identity, even though
LiteLLM/google-auth already fall back to it automatically when no explicit
credential is passed -- the same pattern already supported for Bedrock's
IAM role. Excludes is_vertex from the check, mirroring the Bedrock/Ollama
precedent, and documents the fallback.
- _resolve_api_key() now returns None for Vertex instead of the
  GOOGLE_APPLICATION_CREDENTIALS path, since vertex_ai/gemini-* models
  set both is_vertex and is_gemini, which was causing the file path to
  be written into GEMINI_API_KEY.
- Regenerated configuration-reference.md via generate_reference_docs.py
  instead of hand-editing, and updated the underlying descriptions so
  the doc doesn't drift on next regeneration.

Addresses CodeRabbit review feedbak on cisco-ai-defense#144.
@codecov-commenter

codecov-commenter commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 90.90909% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
skill_scanner/core/analyzers/static.py 87.50% 6 Missing ⚠️
...ill_scanner/core/static_analysis/url_classifier.py 94.11% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

# Conflicts:
#	skill_scanner/core/static_analysis/context_extractor.py
# Conflicts:
#	skill_scanner/core/static_analysis/context_extractor.py
@vineethsai7
vineethsai7 merged commit 704df15 into cisco-ai-defense:main Aug 3, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants