feat: add hybrid analysis datasource - #81
Merged
Merged
Conversation
|
Warning Review limit reachedNext included review available in 28 minutes. View limit detailsLimit 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. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (6)
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. Comment |
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
force-pushed
the
jaspermayone/56-hybrid-analysis
branch
from
September 7, 2026 18:01
98da313 to
d360b63
Compare
Signed-off-by: Jasper Mayone <jasper.mayone@phish.directory>
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #56.
Adds
Phish::HybridAnalysisService, a datasource for the Hybrid Analysis (Falcon Sandbox) public API v2.What it does
The service posts to
search/termsand 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]Scoring
A search hit is not a conviction, and the two search terms do not carry the same weight:
urlsearch matches reports for that exact URL, so a malicious report is about the thing we asked about. Confidence tops out at 0.9.domainsearch 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 isphishinginstead ofsuspicious.Confidence blends how much of the evidence agrees with the worst
threat_scorein 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_SERVICESand caches results for 12 hours, the same shape as Pulsedive. It is registered inServiceFactory, soPhishServiceRetryJoband on demand callers can use it.Other changes
BaseService#connectiontakes arequest_encodingoption. Hybrid Analysis answers a JSON body with a 400, so this service asks for:url_encoded. Every existing caller keeps the:jsondefault.hybrid_analysis.api_key. Documented inREADME.mdandCLAUDE.md. The service raisesAuthenticationErrorwhen 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 failuresbin/rubocop: no offensesbin/brakeman: no warningshttps://claude.ai/code/session_01DMcyASE3TtpFxNmDKzNxjY