Skip to content

feat: add hybrid analysis datasource - #81

Merged
jaspermayone merged 2 commits into
mainfrom
jaspermayone/56-hybrid-analysis
Sep 7, 2026
Merged

jaspermayone merged 2 commits into
mainfrom
jaspermayone/56-hybrid-analysis

Conversation

@jaspermayone

Copy link
Copy Markdown
Member

Closes #56.

Adds Phish::HybridAnalysisService, a datasource for the Hybrid Analysis (Falcon Sandbox) public API v2.

What it does

The service posts to search/terms and asks which sandbox reports mention a domain or a URL. It reads only. Submitting a URL for a new scan needs an elevated key, and a restricted key (the level a free account starts at) gets a 403, so the service never submits.

flowchart TD
    A[check_domain / check_url] --> B{cached?}
    B -- yes --> C[cached result]
    B -- no --> D[reserve rate limit slot]
    D --> E[POST search/terms]
    E --> F{any reports?}
    F -- no --> G[unknown 0.0]
    F -- yes --> H[tally report verdicts]
    H --> I{any malicious?}
    I -- no --> J[suspicious / clean / unknown]
    I -- yes --> K{domain and minority malicious?}
    K -- yes --> L[suspicious]
    K -- no --> M[phishing]
Loading

Scoring

A search hit is not a conviction, and the two search terms do not carry the same weight:

  • A url search matches reports for that exact URL, so a malicious report is about the thing we asked about. Confidence tops out at 0.9.
  • A domain search matches every report whose sample contacted the domain. Shared hosting, URL shorteners and CDNs collect malicious reports without being phishing themselves. Confidence tops out at 0.7, and a domain needs at least half of its reports to say malicious before the verdict is phishing instead of suspicious.

Confidence blends how much of the evidence agrees with the worst threat_score in the page of reports, and never falls below 0.35, which keeps a real hit above the aggregator's 0.3 floor.

Rate limits and caching

A restricted key allows 5 requests per minute and 200 per hour. That is too tight for the per request path, so the service stays out of AggregatorService::DEFAULT_SERVICES and caches results for 12 hours, the same shape as Pulsedive. It is registered in ServiceFactory, so PhishServiceRetryJob and on demand callers can use it.

Other changes

  • BaseService#connection takes a request_encoding option. Hybrid Analysis answers a JSON body with a 400, so this service asks for :url_encoded. Every existing caller keeps the :json default.
  • New credential: hybrid_analysis.api_key. Documented in README.md and CLAUDE.md. The service raises AuthenticationError when it is absent.

Testing

21 new tests cover the verdict mapping, the domain and URL ceilings, the report cap, normalization, form encoding, the api-key header, caching, the local rate limit, 403 and 429.

  • bin/rails test: 388 runs, 0 failures
  • bin/rubocop: no offenses
  • bin/brakeman: no warnings

https://claude.ai/code/session_01DMcyASE3TtpFxNmDKzNxjY

@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 28 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 3acc326c-8fb7-4895-9afd-8e7ea4762afd

📥 Commits

Reviewing files that changed from the base of the PR and between 6eee697 and 2bbfc0b.

📒 Files selected for processing (6)
  • CLAUDE.md
  • README.md
  • app/services/phish/base_service.rb
  • app/services/phish/hybrid_analysis_service.rb
  • app/services/phish/service_factory.rb
  • test/services/phish/hybrid_analysis_service_test.rb

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.

Adds Phish::HybridAnalysisService, which searches the Falcon Sandbox
public API v2 for sandbox reports that mention a domain or a URL.

The service only reads. Submission needs an elevated key, so a
restricted free key gets 403 for it.

A domain search matches every report whose sample contacted the domain,
so shared hosts collect malicious reports without being phishing. Domain
answers are capped below URL answers, and a domain needs most of its
reports to agree before the verdict is phishing rather than suspicious.

The free key allows 5 requests per minute, so the service caches for 12
hours and stays out of AggregatorService::DEFAULT_SERVICES.

Hybrid Analysis rejects a JSON body, so BaseService#connection now takes
a request_encoding option for form encoded requests.

Claude-Session: https://claude.ai/code/session_01DMcyASE3TtpFxNmDKzNxjY
@jaspermayone
jaspermayone force-pushed the jaspermayone/56-hybrid-analysis branch from 98da313 to d360b63 Compare September 7, 2026 18:01
Signed-off-by: Jasper Mayone <jasper.mayone@phish.directory>
@jaspermayone
jaspermayone merged commit c5e6d43 into main Sep 7, 2026
0 of 4 checks passed
@jaspermayone
jaspermayone deleted the jaspermayone/56-hybrid-analysis branch September 7, 2026 18:08
jaspermayone added a commit that referenced this pull request Sep 7, 2026
Two breakages, both from #87 landing alongside #81 and #85.

Migration 20260907120000 exists twice: AddTrustedSourceToServiceKeys from
#85 and CreateIokIndicators from #87. db:test:prepare aborts on the
duplicate before a single test runs. CreateIokIndicators is renumbered to
20260907160000, which is the one that had not shipped when the collision
appeared.

SERVICE_REGISTRY lost the comma after hybrid_analysis when #81 and #87
merged, so service_factory.rb no longer parsed.

Verified the way CI does it: dropped the test database, loaded it from
schema.rb alone, and ran the whole suite. 676 tests, 0 failures. RuboCop,
Brakeman and bundler-audit are clean.

Claude-Session: https://claude.ai/code/session_01AXaht2P613YvPEySvaGX3q
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.

datasource: hybrid-analysis

1 participant