Sicry MCP server
2026년 11월 12일 커밋LLM 기반 OSINT 분석을 통해 AI agent가 17개의 다크웹 엔진으로 Tor/.onion 사이트를 검색하고 가져올 수 있도록 지원합니다.
다른 이름 JacobJandon/Sicry
- 스타
- 20
- Tools
- 6
- 다운로드, 30일
- —
- 최신 버전
- —
- 마지막 커밋
- 2026년 11월 12일
- 라이선스
- —
Sicry MCP란?
Sicry은(는) MCP server입니다. LLM 기반 OSINT 분석을 통해 AI agent가 17개의 다크웹 엔진으로 Tor/.onion 사이트를 검색하고 가져올 수 있도록 지원합니다. 6개 도구를 제공합니다. 예: sicry_check_tor, sicry_renew_identity, sicry_fetch.
프로젝트 README에서 생성된 요약
Sicry MCP server 정보
보안 연구원과 OSINT 분석가는 Sicry를 사용하여 AI agent에게 Tor 네트워크 및 hidden services에 대한 직접적인 접근 권한을 부여할 수 있습니다. 다크웹을 위한 표준화된 인터페이스를 제공함으로써, agent가 로컬 Tor daemon을 통해 검색 및 데이터 추출을 수행할 수 있도록 합니다. 이 MCP server는 OpenAI, Anthropic, Gemini와 같은 주요 LLM provider와 통합되거나, 개인정보 보호를 위해 Ollama를 사용하여 로컬에서 실행할 수 있습니다.
이 시스템은 17개의 서로 다른 다크웹 엔진을 조회하는 sicry_search와 .onion URL을 읽는 sicry_fetch를 포함하여 onion 네트워크 탐색을 위한 특정 도구를 제공합니다. 또한 LLM 기반 분석을 사용하여 위협, 랜섬웨어 또는 기업 스파이 활동에 대한 보고서를 생성하는 OSINT 파이프라인을 포함합니다. 사용자는 sicry_renew_identity를 통해 exit node를 변경하여 identity를 순환하거나, sicry_refine_query를 사용하여 자연어를 최적화된 검색 키워드로 변환할 수 있습니다.
활용 사례
- 1다크웹 위협 인텔리전스분석가는 AI에게 가공되지 않은 onion 사이트 콘텐츠로부터 랜섬웨어 그룹과 그들의 전술에 대한 구조화된 보고서를 생성하도록 요청할 수 있습니다.
- 2자동화된 onion 사이트 스크래핑개발자는 agent에게 여러 hidden service URL을 일괄적으로 fetch하고 분석을 위해 텍스트를 통합하도록 지시할 수 있습니다.
- 3다크웹 쿼리 최적화agent는 더 나은 검색 엔진 결과를 위해 긴 자연어 질문을 짧고 효과적인 키워드 문자열로 변환할 수 있습니다.
- 4엔진 가용성 모니터링사용자는 미션을 시작하기 전에 연결성을 보장하기 위해 17개 다크웹 검색 엔진 전체의 지연 시간과 상태를 확인할 수 있습니다.
프로젝트의 README를 바탕으로 작성되었습니다. 모든 활용 사례는 해당 내용의 인용문과 대조하여 확인합니다.
Sicry MCP 도구 6
README에서 감지됨sicry_check_torsicry_renew_identitysicry_fetchsicry_searchsicry_asksicry_check_engines
| sicry_check_tor | — | |
| sicry_renew_identity | — | |
| sicry_fetch | — | |
| sicry_search | — | |
| sicry_ask | — | |
| sicry_check_engines | — |
구성
ANTHROPIC_API_KEYGEMINI_API_KEYLLM_PROVIDEROLLAMA_MODELOPENAI_API_KEYSICRY_POOL_SIZETOR_CONTROL_PASSWORDTOR_DATA_DIR
| 이름 | 설명 | 유형 |
|---|---|---|
| ANTHROPIC_API_KEY | — | |
| GEMINI_API_KEY | — | |
| LLM_PROVIDER | — | |
| OLLAMA_MODEL | — | |
| OPENAI_API_KEY | — | |
| SICRY_POOL_SIZE | — | |
| TOR_CONTROL_PASSWORD | — | |
| TOR_DATA_DIR | — |
자동 검사
2026년 11월 14일에 실행됨전체 보고서 →아직 인증되지 않았습니다. 서버는 80점 이상의 점수, 심각한 결함 없음, 그리고 검사에 충분한 데이터를 갖추어야 합니다. 검사 방식 · 점수를 높이기 위해 수정할 항목
- 소스 저장소 연결 및 접근 가능jacobjandon/sicry is public and reachablegithub.com/jacobjandon/sicry ↗통과
- 패키지가 이 저장소를 소스로 명시검사되지 않음
- 빌드 출처(Sigstore 증명)검사되지 않음
- 오픈 소스 라이선스 (OSI)No license결함 발견
- 최근 1년 내 커밋 또는 릴리스Last commit or release 2026-11-12github.com/jacobjandon/sicry ↗통과
- OpenSSF Scorecard검사되지 않음
- 패키지 이름이 인기 패키지와 유사하지 않음검사되지 않음
- 패키지 및 해당 종속성에 중요한 보안 권고 없음검사되지 않음
- 모델에 대한 숨겨진 지침 없음6 tool descriptions and the README read; no override phrases, credential paths or hidden characters통과
- 파괴적인 도구에 라벨 표시됨No tool named like delete, drop or exec통과
- 원격 엔드포인트가 MCP 핸드셰이크에 응답검사되지 않음
README
GitHub에서 보기SICRY™ — Tor/Onion Network Access Layer for AI Agents
by JacobJandon · github.com/JacobJandon/Sicry
One Python file. Drop it into any project and your AI agent gets full access to the Tor/.onion dark web — the same clean tool interface agents use for the regular internet, just now for hidden services.
Robin's complete search engine catalogue (17 engines) and OSINT pipeline are baked in directly. No Robin install needed. No extra processes. No config beyond a .env file.
pip install requests[socks] beautifulsoup4 python-dotenv stem
apt install tor && tor &
cp .env.example .env # add one API key (or use Ollama — no key needed)
python sicry.py check # → CONNECTED via Tor | exit IP: 185.220.101.5
Contents
- What SICRY™ does
- Installation
- Quickstart
- All nine functions
- Tool schemas (Anthropic / OpenAI / Gemini)
- Framework integration
- CLI reference
- The full OSINT pipeline
- Analysis modes
- 17 search engines
- Environment variables
- Tor setup
- Architecture
- Troubleshooting
- Credits
What SICRY™ does
SICRY™ gives AI agents exactly 6 tools — the same 6 they already know how to use for the clearnet, just now running over Tor:
| SICRY™ tool | Clearnet equivalent | What it does |
|---|---|---|
sicry_check_tor |
health check | Verify Tor is active, get exit IP |
sicry_renew_identity |
reset session | Rotate circuit, get new exit node |
sicry_fetch |
fetch_url() / browser_read_page() |
Read any URL or .onion via Tor |
sicry_search |
web_search() / brave_search() |
Query 17 dark web search engines |
sicry_ask |
analyze() / summarize() |
LLM OSINT report from raw content |
sicry_check_engines |
ping / health check | Latency + status for all 17 engines |
Plus three quality-improvement helpers (Robin patterns, call directly):
| Helper | What it does |
|---|---|
refine_query(query) |
LLM: natural language → ≤5-word dark web query |
filter_results(query, results) |
LLM: pick top 20 most relevant from all raw results |
scrape_all(urls) |
Concurrent batch-fetch → {url: "title - text"} dict |
Installation
Requirements
- Python 3.10+
- Tor daemon running locally
- pip packages (below)
1. Install Tor
Linux (Debian/Ubuntu):
apt install tor
tor &
macOS:
brew install tor
tor &
Custom DataDirectory (recommended for renew_identity):
cat > /tmp/sicry_tor.conf << 'EOF'
SocksPort 9050
ControlPort 9051
CookieAuthentication 1
DataDirectory /tmp/tor_data
EOF
tor -f /tmp/sicry_tor.conf &
When using a custom config, set TOR_DATA_DIR=/tmp/tor_data in your .env.
2. Install Python dependencies
pip install -r requirements.txt
Or manually:
pip install requests[socks] beautifulsoup4 python-dotenv stem
# Optional — only needed if using the MCP server
pip install mcp
# Optional — only needed if using OpenAI/Anthropic/Gemini LLM backends
pip install openai # for OpenAI
pip install anthropic # for Anthropic/Claude
pip install google-generativeai # for Gemini
3. Configure .env
cp .env.example .env
Minimum config — pick one LLM:
# No-key option (local inference):
LLM_PROVIDER=ollama
OLLAMA_MODEL=llama3.2
# OpenAI:
LLM_PROVIDER=openai
OPENAI_API_KEY=sk-...
# Anthropic:
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
# Gemini:
LLM_PROVIDER=gemini
GEMINI_API_KEY=AIza...
Note:
ask(),refine_query(), andfilter_results()need an LLM key. All other tools (search,fetch,check_tor,renew_identity,check_search_engines,scrape_all) work with no key at all.
Quickstart
# Verify Tor is running
python sicry.py check
# → CONNECTED via Tor | exit IP: 185.220.101.5 | error: None
# Search the dark web
python sicry.py search "ransomware data leak" --max 10
# Fetch a .onion page
python sicry.py fetch http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion
# Print tool schemas for your framework
python sicry.py tools # Anthropic format (default)
python sicry.py tools --format openai # OpenAI format
python sicry.py tools --format gemini # Gemini format
# Rotate Tor identity
python sicry.py renew
# Start MCP server (for Claude Desktop / Cursor / Zed)
python sicry.py serve
In Python:
import sicry
# Verify Tor
print(sicry.check_tor())
# → {"tor_active": True, "exit_ip": "185.220.101.5", "error": None}
# Search
results = sicry.search("credential dump")
# → [{"title": "...", "url": "http://...onion/...", "engine": "Ahmia"}, ...]
# Fetch
page = sicry.fetch("http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion")
# → {"url": "...", "is_onion": True, "status": 200, "title": "Ahmia", "text": "...", "links": [...]}
All nine functions
check_tor() → dict
Verify Tor is running and the machine is routing through a Tor exit node.
r = sicry.check_tor()
# {"tor_active": True, "exit_ip": "185.220.101.5", "error": None}
# {"tor_active": False, "exit_ip": None, "error": "connection refused"}
Call this first. All other network functions silently fail if Tor is down.
renew_identity() → dict
Rotate the Tor circuit — get a new exit node and a fresh identity.
r = sicry.renew_identity()
# {"success": True, "error": None}
Auth is attempted in order:
TOR_CONTROL_PASSWORDenv var (if you setHashedControlPasswordin torrc)- Cookie file from
TOR_DATA_DIRenv var - Cookie file from common system paths (
/tmp/tor_data,/var/lib/tor,~/.tor,/run/tor) - Empty-string / null auth (Tor with no password at all)
Works out of the box with SICRY™'s recommended torrc (cookie auth). See Tor setup.
fetch(url) → dict
Fetch any URL through Tor — works for clearnet and .onion hidden services.
r = sicry.fetch("http://somemarket.onion/listings")
# {
# "url": "http://somemarket.onion/listings",
# "is_onion": True,
# "status": 200,
# "title": "Market Listings",
# "text": "Plain text, HTML stripped, up to 8000 chars",
# "links": [{"text": "Link label", "href": "http://..."}, ...], # up to 80 links
# "error": None
# }
- URLs without
http:///https://gethttp://prepended automatically. textis HTML-stripped, whitespace-collapsed, truncated toMAX_CONTENT_CHARS(default 8000).- Always returns a dict — never raises.
search(query, engines=None, max_results=20, max_workers=8) → list[dict]
Search across 17 dark web search engines simultaneously.
# All 17 engines in parallel
results = sicry.search("leaked database credentials")
# [{"title": "...", "url": "http://...onion/...", "engine": "Ahmia"}, ...]
# Specific engines only
results = sicry.search("ransomware", engines=["Ahmia", "Tor66", "Ahmia-clearnet"])
# More results
results = sicry.search("bitcoin mixer", max_results=50)
- Results are deduplicated by URL across all engines.
enginesis case-insensitive. Unknown engine names are silently skipped.- Always returns a list — never raises.
scrape_all(urls, max_workers=5) → dict
Batch-fetch multiple pages concurrently and return {url: content} ready for an LLM.
pages = sicry.scrape_all(search_results[:10])
# {
# "http://site1.onion/page": "Page Title - full page text...(truncated)",
# "http://site2.onion/page": "Page Title - full page text",
# ...
# }
combined = "\n\n".join(pages.values())
- Input is the raw output of
search()— list of{"title", "url"}dicts. - Content is capped at 2000 chars per page with
...(truncated)marker. - Uses Robin's pattern:
"title - text"format primes the LLM with context. - Pages that fail are silently dropped (only reachable pages returned).
refine_query(query, provider=None) → str
LLM-refine a natural language query into ≤5 focused words for dark web search engines.
q = sicry.refine_query("I want to find ransomware groups that targeted hospitals in 2026")
# → "hospital ransomware 2026 leak"
q = sicry.refine_query("has acme.com appeared in any data breaches")
# → "acme.com breach credentials"
- Falls back to the original query if no LLM key is set. Never raises.
- This is a Robin pattern — dark web indexes respond much better to short keywords than natural language.
- Use before
search()for significantly better results.
filter_results(query, results, provider=None) → list[dict]
LLM-filter a list of search results to keep only the top 20 most relevant.
best = sicry.filter_results("hospital ransomware 2026", raw_results)
# Returns at most 20 results, selected by the LLM for relevance
- Falls back to
results[:20]if no LLM key is set. Never raises. - Automatically retries with truncated titles if the LLM rate-limits on large payloads.
- Use after
search()to reduce noise before scraping.
ask(content, query="", mode="threat_intel", custom_instructions="", provider=None) → str
Analyse dark web content with an LLM and return a structured OSINT report.
report = sicry.ask(
content="\n\n".join(pages.values()),
query="hospital ransomware groups",
mode="ransomware",
)
print(report) # Structured report: indicators, TTPs, threat actor profile, next steps
Modes:
| Mode | Alias | Focus |
|---|---|---|
threat_intel |
(default) | General OSINT — artifacts, insights, next steps |
ransomware |
ransomware_malware |
Malware/C2/MITRE TTPs, victim orgs, detection |
personal_identity |
PII/breach exposure, severity, protective actions | |
corporate |
corporate_espionage |
Leaked credentials/code/docs, IR steps |
# Add custom focus to any mode
report = sicry.ask(
content,
mode="threat_intel",
custom_instructions="Focus on cryptocurrency wallets and mixer services",
)
- If no LLM key is set, returns a
[SICRY™: ...]error string — never raises. - Content is truncated to
MAX_CONTENT_CHARS(default 8000) before sending to the LLM.
check_search_engines(max_workers=8) → list[dict]
Ping all 17 engines via Tor and return per-engine status and latency.
results = sicry.check_search_engines()
# [
# {"name": "Ahmia", "status": "up", "latency_ms": 1240, "error": None},
# {"name": "Kaizer", "status": "down", "latency_ms": None, "error": "timeout"},
# ...
# ]
live = [r for r in results if r["status"] == "up"]
print(f"{len(live)}/17 engines alive")
fastest = min(live, key=lambda x: x["latency_ms"])
print(f"Fastest: {fastest['name']} ({fastest['latency_ms']}ms)")
- Results maintain the original engine order.
- Use before
search()to avoid wasting time on dead engines.
Tool schemas
SICRY™ exposes all 6 tools in the native format for each major framework. All three formats are always in sync.
import sicry
sicry.TOOLS # Anthropic / Claude format (input_schema)
sicry.TOOLS_OPENAI # OpenAI function-calling format (type: "function")
sicry.TOOLS_GEMINI # Google Gemini function declarations
Print any of them:
python sicry.py tools # Anthropic (default)
python sicry.py tools --format openai
python sicry.py tools --format gemini
Tools exposed:
| Tool name | Required args | Optional args |
|---|---|---|
sicry_check_tor |
(none) | |
sicry_renew_identity |
(none) | |
sicry_fetch |
url |
|
sicry_search |
query |
max_results (int), engines (list) |
sicry_ask |
content |
query, mode, custom_instructions |
sicry_check_engines |
(none) | max_workers (int) |
Framework integration
dispatcher
All frameworks share one dispatcher — call it with the tool name and input dict:
result = sicry.dispatch(tool_name, tool_input)
# Returns: dict | list | str (matches the tool's documented return type)
# Raises: ValueError if tool_name is unknown
Anthropic / Claude
import anthropic, sicry, json
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "Search dark web for recent credential leaks from banks"}]
while True:
resp = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
system="You are a dark-web OSINT analyst. Always verify Tor before searching.",
tools=sicry.TOOLS, # <- Anthropic format
messages=messages,
)
if resp.stop_reason != "tool_use":
print(next(b.text for b in resp.content if hasattr(b, "text")))
break
tool_results = []
for block in resp.content:
if block.type == "tool_use":
result = sicry.dispatch(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result, default=str),
})
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": tool_results})
OpenAI / GPT
from openai import OpenAI
import sicry, json
client = OpenAI()
messages = [
{"role": "system", "content": "You are a dark-web OSINT analyst."},
{"role": "user", "content": "Has acme.com appeared in any dark web leaks?"},
]
while True:
resp = client.chat.completions.create(
model="gpt-4o",
tools=sicry.TOOLS_OPENAI, # <- OpenAI format
messages=messages,
)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content)
break
for call in msg.tool_calls:
result = sicry.dispatch(
call.function.name,
json.loads(call.function.arguments),
)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, default=str),
})
Google Gemini
import google.generativeai as genai
import sicry, json
genai.configure(api_key="YOUR_GEMINI_API_KEY")
model = genai.GenerativeModel(
"gemini-2.5-flash",
tools=[{"function_declarations": sicry.TOOLS_GEMINI}], # <- Gemini format
system_instruction="You are a dark-web OSINT analyst.",
)
chat = model.start_chat()
resp = chat.send_message("Find mentions of acme.com on dark web forums")
while True:
fn_calls = [p.function_call for p in resp.parts
if hasattr(p, "function_call") and p.function_call.name]
if not fn_calls:
for part in resp.parts:
if hasattr(part, "text"):
print(part.text)
break
tool_responses = []
for fn_call in fn_calls:
result = sicry.dispatch(fn_call.name, dict(fn_call.args))
tool_responses.append(
genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name=fn_call.name,
response={"result": json.dumps(result, default=str)},
)
)
)
resp = chat.send_message(tool_responses)
LangChain
from langchain.tools import StructuredTool
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
import sicry
tools = [
StructuredTool.from_function(name="sicry_check_tor",
func=sicry.check_tor,
description="Verify Tor is active. Call before any dark web operation."),
StructuredTool.from_function(name="sicry_renew_identity",
func=sicry.renew_identity,
description="Rotate Tor circuit — new exit node and identity."),
StructuredTool.from_function(name="sicry_fetch",
func=sicry.fetch,
description="Fetch any URL or .onion hidden service via Tor."),
StructuredTool.from_function(name="sicry_search",
func=lambda query, max_results=20: sicry.search(query, max_results=max_results),
description="Search 17 dark web engines. Returns title/url/engine list."),
StructuredTool.from_function(name="sicry_ask",
func=sicry.ask,
description="Analyse dark web content. mode: threat_intel|ransomware|personal_identity|corporate"),
StructuredTool.from_function(name="sicry_check_engines",
func=sicry.check_search_engines,
description="Ping all 17 search engines. Returns status + latency per engine."),
]
agent = initialize_agent(
tools,
ChatOpenAI(model="gpt-4o"),
agent=AgentType.OPENAI_FUNCTIONS,
verbose=True,
)
agent.run("Search the dark web for ransomware activity targeting the healthcare sector")
CrewAI
from crewai import Agent, Task, Crew
from langchain.tools import StructuredTool
import sicry
sicry_tools = [
StructuredTool.from_function(name="sicry_check_tor",
func=sicry.check_tor,
description="Verify Tor is active."),
StructuredTool.from_function(name="sicry_search",
func=lambda query: sicry.search(query, max_results=20),
description="Search 17 dark web engines."),
StructuredTool.from_function(name="sicry_fetch",
func=sicry.fetch,
description="Fetch any .onion URL via Tor."),
StructuredTool.from_function(name="sicry_ask",
func=sicry.ask,
description="LLM OSINT analysis. mode: threat_intel|ransomware|personal_identity|corporate"),
StructuredTool.from_function(name="sicry_check_engines",
func=sicry.check_search_engines,
description="Ping all 17 search engines. Returns status + latency."),
]
analyst = Agent(
role="Dark Web OSINT Analyst",
goal="Investigate dark web threats and produce structured intelligence reports",
backstory="Expert in dark web monitoring and threat intelligence",
tools=sicry_tools,
verbose=True,
)
task = Task(
description="Search for ransomware groups targeting hospitals. Fetch top results and produce an intelligence report.",
expected_output="Structured OSINT report with threat actors, TTPs, indicators, and next steps.",
agent=analyst,
)
Crew(agents=[analyst], tasks=[task]).kickoff()
MCP (Claude Desktop / Cursor / Zed)
Start the server:
python sicry.py serve
Add to ~/.config/claude/claude_desktop_config.json:
{
"mcpServers": {
"sicry": {
"command": "python",
"args": ["/absolute/path/to/sicry.py", "serve"]
}
}
}
Cursor (settings.json):
"mcp.servers": {
"sicry": {
"command": "python /absolute/path/to/sicry.py serve"
}
}
The 6 SICRY™ tools are registered automatically via FastMCP. Requires: pip install mcp
OpenClaw
mkdir -p ~/.openclaw/workspace/skills/sicry
cp sicry.py openclaw_skill/SKILL.md ~/.openclaw/workspace/skills/sicry/
CLI reference
python sicry.py <command> [options]
| Command | Options | Description |
|---|---|---|
check |
Verify Tor is running, show exit IP | |
renew |
Rotate Tor circuit | |
search <query> |
--max N (default 10), --engine NAME (repeatable) |
Search dark web |
fetch <url> |
Fetch URL via Tor, print text | |
tools |
--format anthropic|openai|gemini |
Print tool schemas as JSON |
serve |
Start MCP server |
Examples:
python sicry.py check
python sicry.py renew
python sicry.py search "ransomware healthcare" --max 15
python sicry.py search "bitcoin mixer" --engine Ahmia --engine Tor66
python sicry.py fetch http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion
python sicry.py tools --format openai | python -m json.tool
python sicry.py serve
The full OSINT pipeline
This is the recommended workflow. Each step applies a Robin pattern that makes a measurable difference in result quality:
import sicry
# Step 1: Verify Tor
status = sicry.check_tor()
if not status["tor_active"]:
raise RuntimeError(f"Tor not active: {status['error']}")
print(f"Tor active. Exit IP: {status['exit_ip']}")
# Step 2: Health-check engines (skip dead ones)
engine_status = sicry.check_search_engines()
live = [e for e in engine_status if e["status"] == "up"]
live_names = [e["name"] for e in live]
print(f"{len(live)}/17 engines alive: {', '.join(live_names[:5])}...")
# Step 3: Refine query (Robin quality pattern)
raw_query = "ransomware groups targeting hospital systems 2026"
query = sicry.refine_query(raw_query)
print(f"Refined: '{raw_query}' -> '{query}'")
# Step 4: Search (query only live engines in parallel)
raw_results = sicry.search(
query,
engines=live_names, # skip engines we know are down
max_results=50,
)
print(f"{len(raw_results)} raw results")
# Step 5: Filter to best 20 (Robin quality pattern)
best = sicry.filter_results(query, raw_results)
print(f"Filtered to {len(best)} most relevant")
# Step 6: Batch scrape concurrently
pages = sicry.scrape_all(best[:10], max_workers=5)
print(f"Scraped {len(pages)} pages")
# Step 7: OSINT analysis
combined = "\n\n".join(f"[{url}]\n{text}" for url, text in pages.items())
report = sicry.ask(
combined,
query=query,
mode="ransomware",
custom_instructions="Focus on victim organisations and ransom demands.",
)
print(report)
# Step 8: Rotate identity when done
sicry.renew_identity()
Analysis modes
All four modes produce a structured sectioned report. Pass raw .onion text or scrape_all() output.
threat_intel (default)
General dark web OSINT. Best for initial investigation.
Output sections: Input Query · Source Links · Investigation Artifacts · Key Insights · Next Steps
report = sicry.ask(content, query="acme.com breach", mode="threat_intel")
ransomware
Alias: ransomware_malware
Malware intelligence. Extracts C2 domains, file hashes, MITRE ATT&CK TTPs, victim sectors.
Output sections: Input Query · Source Links · Malware/Ransomware Indicators · Threat Actor Profile · Key Insights · Next Steps
report = sicry.ask(content, query="LockBit hospital", mode="ransomware")
personal_identity
PII exposure analysis. Surfaces SSNs, emails, passport data, breach sources, risk severity.
Output sections: Input Query · Source Links · Exposed PII Artifacts · Breach/Marketplace Sources · Exposure Risk Assessment · Key Insights · Next Steps
report = sicry.ask(content, query="john.doe@email.com", mode="personal_identity")
corporate
Alias: corporate_espionage
Corporate threat intelligence. Detects leaked credentials, source code, internal documents.
Output sections: Input Query · Source Links · Leaked Corporate Artifacts · Threat Actor/Broker Activity · Business Impact Assessment · Key Insights · Next Steps
report = sicry.ask(content, query="acme.com corporate leak", mode="corporate")
Sicry MCP 질문
Sicry MCP는 어떤 도구를 제공하나요?
6개 도구를 제공합니다. 예: sicry_check_tor, sicry_renew_identity, sicry_fetch, sicry_search, sicry_ask.
Sicry를 사용하려면 API key가 필요한가요?
검색, fetch, Tor 체크, identity 갱신 및 엔진 상태 확인에는 키가 필요하지 않습니다. LLM 분석 기능만 제공자 키 또는 로컬 Ollama 모델이 필요합니다.
Sicry는 몇 개의 다크웹 검색 엔진을 조회하나요?
Sicry는 17개의 엔진을 병렬로 검색하며 URL 기준으로 중복된 결과를 제거합니다.
분석을 위해 어떤 LLM provider를 사용할 수 있나요?
LLM_PROVIDER 설정을 통해 OpenAI, Anthropic, Gemini 또는 로컬 Ollama 추론을 지원합니다.
Sicry를 실행하려면 Tor daemon이 구동 중이어야 하나요?
네, Tor가 로컬에 설치되어 실행 중이어야 합니다. Sicry는 먼저 연결을 확인하고 exit IP를 보고합니다.
Sicry가 새로운 identity를 얻기 위해 Tor circuit를 순환할 수 있나요?
네, renew_identity를 통해 circuit와 exit node를 순환하며 password, cookie, null 인증을 순서대로 시도합니다.