摘要
新增 tools/scanmalware_search.yaml:查询 ScanMalware 公开扫描归档,无需 API Key。支持 5 种模式:domain、url、ip、subdomains、smql。与其他 *_search 工具一致,默认 enabled: false。
披露:我是 ScanMalware(瑞典 Triop AB)的开发者。
Summary
Adds one file, tools/scanmalware_search.yaml, a read-only lookup tool for the public ScanMalware scan archive (https://scanmalware.com). ScanMalware renders submitted URLs in a sandboxed browser and indexes each scan (phishing and malware verdicts, network requests, TLS/JARM, favicon hash, technologies, screenshots) for search. The tool only reads the archive; it never submits a scan.
Disclosure: I run ScanMalware (Triop AB, Sweden).
No API key. Unlike the other *_search tools (fofa_search, zoomeye_search, quake_search, shodan_search, virustotal_search), it works on a fresh install with nothing to configure. The anonymous rate limit is 600 requests/minute. To check:
curl -s "https://scanmalware.com/api/v1/domains/example.com/scans?limit=1"| mode | target | returns |
|---|---|---|
domain | hostname | recent scans of the host, plus the verdict from its latest assessed scan |
url | full URL | scans of exactly that URL, plus its verdict |
ip | IPv4 / IPv6 | domains resolving to the address in Certificate Transparency DNS records, and scans that contacted it (context only, no verdict) |
subdomains | domain | passive subdomains from CT DNS records, the scan archive, and hosts the browser actually contacted during scans |
smql | SMQL query | archive search for pivots such as jarm:, favicon_hash:, asn:, technology:, ocr: |
Design notes
- Verdicts are never borrowed. A verdict comes only from a scan whose own URL is the target (
matched_onincludesurl). Scans that merely redirected to the host are listed separately with no verdict, andurlmode never applies another page's verdict from the same host. - An IP gets context, never a verdict. A page that loaded something from an address says nothing about the address itself.
lowis reported asno_findings, never as safe.malicious,highandcriticalmap tomalicious. If the newest scan was not assessed (for example the page never loaded) it is skipped in favour of an older assessed one, and an unrecognised risk level is returned as-is rather than guessed.enabled: falseby default, like the other search tools. Since this one needs no key, the reason is privacy rather than configuration: lookups send the queried domain, URL or IP to scanmalware.com. The API's own/hostsresponse documents astreamsource for hostnames that were queried against it and resolve in public DNS, so the tool description tells users not to look up targets that must stay private.- Parameters use
flagformat parsed with argparse, ashttp-framework-test.yamldoes, andtargetusescombined(--target=...) so an SMQL query that starts with-is not read as an option. - Requests identify as
scanmalware-cyberstrikeai/1.0. The only dependency isrequests, already inrequirements.txt.
Testing
- Loaded with
config.LoadToolsFromDir("tools")(91 tools, no warnings) and called throughmcp.Server.CallToolandExecutor.ExecuteToolwith the tool enabled, against the live API, for all five modes, plus an input the API rejects (localhost, returned asisError) and a call missing the requiredmode(the executor's own error). - Verdict attribution checked against a local fixture server whose rows put a redirector first, a not-assessed scan next, and a different URL on the same host. Removing each guard in turn made the check fail.
go build ./...,go vet ./internal/config ./internal/security,go test ./internal/config ./internal/security ./internal/handler ./internal/mcpandgo test -race ./internal/processguard ./internal/runleasepass on Go 1.25.0. The repository's workflow path filter does not includetools/, so no CI runs on this PR.
I left README.md and README_CN.md unchanged to keep this to one file. Happy to add scanmalware_search to the tool list there, or to the threat-intelligence group in internal/workflow/draft_generator.go, if you would like.