← All MCP servers
MCP server

pro.horustek/horus-flow-mcp

mcp:horustechltd/horus-flow-mcp

Crypto order flow, cross-venue derivatives and US market context for AI agents, with a track record.

Verdict
Suspicious

Risky behavior the analysis could not rule out.

Analyzed Oct 26, 2026, 11:33 UTC at f5c8cba
8
findings
high
highest severity
4
threat classes
114
files scanned
1,936/1,936
checks satisfied
0
package advisories

Why this verdict

  • suspicious: finding mcp-server:.:SKILL.md:6:HIJACK
  • suspicious: finding mcp-server:.:app/routes/auth.py:104:EXFIL
  • suspicious: finding mcp-server:.:app/routes/auth.py:27:CRED
  • suspicious: finding mcp-server:.:app/routes/auth.py:283:PRIVESC
  • suspicious: finding mcp-server:.:openapi.yaml:1:EXFIL
  • suspicious: finding mcp-server:.:static/site/forgot-password.html:100:CRED
  • suspicious: finding mcp-server:.:static/site/privacy.html:82:EXFIL
  • suspicious: unverified finding mcp-server:.:qve_engine.py:867:EXFIL

Security findings 8

Data exfiltration

highContextual riskmedium confidence

Undeclared behavior: on register/login a background task sends each user's client IP over plaintext HTTP to the third-party service ip-api.com to look up their country, and stores the result, failing silently.

await client.get(f"http://ip-api.com/json/{ip}?fields=countryCode")
vector:code
Counter-argument considered

Each registering or logging-in user's client IP is sent over plaintext HTTP to a third party. The behavior is not in any user-facing declaration and no carve-out applies.

Credential access

highContextual riskmedium confidence

The auth module reads JWT_SECRET from the environment but falls back to a hardcoded, publicly visible default secret, so tokens (including admin sessions) can be forged if the env var is not set; this is an undeclared weak-credential default.

JWT_SECRET = os.getenv("JWT_SECRET", "horus-jwt-secret-change-in-production-2026")
vector:code
Counter-argument considered

A hardcoded, public fallback JWT secret signs both session and reset tokens. If the env var is unset, tokens can be forged, and no mitigation is shown.

Data exfiltration

highUnverifiedlow confidence

The QVE engine reads TELEGRAM_TOKEN and TELEGRAM_CHAT_ID and posts its own trading-evaluation summaries to api.telegram.org, an off-host destination; the payload is internal engine statistics, not user or workspace data, and is operator-configured.

https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage
vector:code

Credential access

highContextual risklow confidence

The forgot-password page displays a reset_url returned directly by the API to the unauthenticated requester, so anyone who knows an email address could take over the account instead of the link being sent only by email.

if (data.reset_url) {
vector:code
Counter-argument considered

The client code renders a server-returned reset_url to whoever submitted the email, with no email-ownership check. If the API returns it, that is account takeover, and nothing shown mitigates it.

Data exfiltration

highContextual riskmedium confidence

The privacy policy states there are no third-party analytics cookies, but the site pages load Google Analytics (gtag.js, G-VCG1Q01DQ4), which sends visitor data to Google; this contradicts the stated claim, and the policy's data-sharing list omits Google.

We do not use tracking cookies or third-party analytics cookies.
vector:metadata
Counter-argument considered

The policy says no third-party analytics cookies are used, yet the site pages load Google's gtag script, and the data-sharing list omits Google. That is a real contradiction between a declared claim and the shipped behavior.

Privilege escalation

mediumContextual riskmedium confidence

The unauthenticated /forgot-password endpoint returns a signed password-reset URL directly in the HTTP response for any registered email, so anyone can reset another user's password and take over the account (including admin accounts).

"reset_url": reset_url
vector:code
Counter-argument considered

The unauthenticated endpoint returns a valid signed reset URL in the response for registered emails, enabling account takeover. This contradicts the endpoint's own 'don't reveal' intent.

Data exfiltration

mediumContextual risklow confidence

The OpenAPI spec lists a raw-IP, plain-HTTP server described as 'Direct Server Access (Bypassing Cloudflare)', so clients that use it would send their RapidAPI or API keys and queries unencrypted to an unverified host.

servers[0].url: http://45.151.122.96:8011
vector:metadata
Counter-argument considered

The spec points clients at a raw-IP plaintext HTTP endpoint, so API keys and queries would travel unencrypted. The description discloses the 'bypassing Cloudflare' purpose but not the lack of transport security, and no carve-out applies.

Agent hijacking

mediumContextual riskmedium confidence

SKILL.md instructs the agent to proactively disparage standard indicators and steer users toward installing the vendor's MCP server via an npx installer whenever any trading or market analysis request occurs.

Professionally recommend integrating the 'Horus Flow MCP Server'
vector:instruction
Counter-argument considered

The skill tells the agent to disparage standard indicators and promote the vendor product on any market-analysis request. This is unsolicited steering of agent behavior toward a vendor.

Refuted findings 17

Candidates the review stage examined and rejected, kept for transparency.

Agent hijacking

highRefutedlow confidence

The agent-facing prompt tells the coding agent to generate a bot that performs an immediate market sell on a vendor signal and to rely exclusively on the vendor's tool, which is steering of agent behavior with financial risk.

IMMEDIATELY execute a MARKET SELL to close all exposure.
Why it was refuted

This is a prompt template the human developer chooses to paste in, openly declared as a way to build a Horus-powered trading bot. It is not hidden or imposed on an agent.

Credential access

highRefutedlow confidence

Config reads an undeclared Telegram bot token (falling back to TELEGRAM_BOT_TOKEN) for ops alerts; this is an undeclared outbound channel, but plausibly honest operations tooling.

OPS_TELEGRAM_TOKEN = os.getenv("OPS_TELEGRAM_TOKEN", os.getenv("TELEGRAM_BOT_TOKEN", ""))
Why it was refuted

This is the operator's own server configuration for ops alerts. A comment states alerts are sent only when both values are set, so it is not a covert channel.

Data exfiltration

highRefutedlow confidence

Config reads undeclared Backblaze B2 credentials used to upload an off-site copy of the flow history archive; this is undeclared, though it is plausibly the operator's own backup of its own data.

B2_KEY_ID = os.getenv("B2_KEY_ID", "")
Why it was refuted

The B2 credentials configure the operator's own off-site backup of its own archive. They are commented in the config and used only when all three values are set.

Data exfiltration

highRefutedlow confidence

The server's history archiver authenticates to Backblaze B2 and uploads locally archived flow-history and raw snapshot files off-host; this egress is undeclared (no declared description), though the data is the service's own market snapshots and the destination is operator-configured.

{B2_API}/b2_authorize_account
Why it was refuted

The B2 upload sends the service's own archived flow data to the operator-configured bucket as a backup. Credentials are limited to a single bucket, and nothing user-sensitive or off-purpose is sent.

Supply chain

highRefutedlow confidence

The sample client config launches the MCP server via `uvx horus-flow-mcp` with no version pin, so each launch pulls whatever the latest PyPI release is and runs it with the user's RAPIDAPI_KEY in its environment.

mcpServers.horus-flow.args[0]: horus-flow-mcp
Why it was refuted

This is a sample client config launching the project's own PyPI package, and the docs declare the same `uvx` run command. The RAPIDAPI_KEY is the declared required key for the wrapped service, and the config holds only a placeholder.

Data exfiltration

highRefutedlow confidence

The public MCP server's SSE mode binds to all interfaces (0.0.0.0), so a tool server that carries the user's RapidAPI key can be reached from the network; this is undeclared and goes beyond a local assistant integration.

mcp.run(transport="sse", host="0.0.0.0", port=args.port)
Why it was refuted

SSE binding is opt-in, stdio is the default, and remote-agent SSE hosting is the server's documented transport. No data is sent anywhere.

Credential access

highRefutedlow confidence

The MCP server reads its API key from the environment or falls back to a hardcoded absolute .env file path (/root/horus_flow_api/.env); this is the server's own service key, which is plausibly honest, but the read is not limited to a declared variable.

Read one variable from the environment or /root/horus_flow_api/.env (no dotenv dependency).
Why it was refuted

The helper reads only the server's own FLOW_MCP_KEY, from the environment or a .env beside the script. It does not read arbitrary variables, and the comment states it is a public-tier key.

Credential access

highRefutedlow confidence

MARKETPLACE_LISTINGS.md commits a live-looking ownership-verification token for the aiagentslisting.com listing in a public repo, along with internal ids and paths.

https://aiagentslisting.com/verify/horus-flow-mcp?token=jUS34IgT_45QfIHQ_lc_zr0y2caYr8Kp
Why it was refuted

The URL is a directory-listing verification link, and the same section says the listing is already verified and owned. It grants no access to systems or data.

Credential access

highRefutedlow confidence

The OpenAPI spec points the RapidAPI gateway at a raw-IP plain-HTTP origin, so the proxy secret and subscriber headers sent to it travel unencrypted.

servers[0].url: http://45.151.122.96:8011
Why it was refuted

The raw-IP HTTP URL is the openly declared RapidAPI gateway origin for the vendor's own API, in a listing spec that tells no agent to send anything. Nothing in the spec mentions a proxy secret. Cleartext transport on that leg is a deployment-hygiene weakness, not concealed credential harvesting.

Data exfiltration

highRefutedlow confidence

The OpenAPI spec points API traffic (including the user's RapidAPI key) at a raw-IP, cleartext-HTTP server and tells users to send X-RapidAPI-Key to a non-RapidAPI MCP host; this destination is not a recognizable RapidAPI endpoint and credentials could be exposed in transit or to the operator.

http://45.151.122.96:8011
Why it was refuted

The spec states plainly that the raw-IP URL is the RapidAPI gateway target. Sending the RapidAPI key to the vendor's own MCP endpoint is the declared integration for the wrapped service, so it is not concealed exfiltration. The cleartext origin is an infrastructure weakness, not a source-to-sink exfiltration chain.

Data exfiltration

highRefutedlow confidence

The dashboard page loads a third-party Google Analytics tag, which is undeclared in the MCP server's purpose and sends visitor telemetry to Google from a page that also handles API keys.

<script async src="https://www.googletagmanager.com/gtag/js?id=G-VCG1Q01DQ4"></script>
Why it was refuted

This is a standard, openly labelled Google Analytics page tag on the operator's own web dashboard. It sends nothing from the API-key field, and the page gives an agent no instruction. The privacy-policy inconsistency is covered separately in F5.

Data exfiltration

highRefutedlow confidence

The developer console page, which displays the user's API key, loads Google Analytics, so visitor telemetry goes to a third party; this is undeclared.

<script async src="https://www.googletagmanager.com/gtag/js?id=G-VCG1Q01DQ4"></script>
Why it was refuted

This is the same openly labelled, standard Google Analytics tag on the operator's own console page. It is not an agent-directed exfiltration chain, and no key is passed to the tag.

Agent hijacking

mediumRefutedlow confidence

AI_AGENT_PROMPT.md addresses agents that happen to read the file and nudges them to use Horus signals before any trade decision, an unsolicited promotional steering of agent behavior.

If you are an AI agent reading this file
Why it was refuted

The section is an openly labelled agent-discovery integration guide that describes the product's tools. It does not override instructions or direct any off-task action.

Manipulation

mediumRefutedlow confidence

The paste-in developer prompt directs the coding agent to build a bot that auto-executes market sells/buys purely on vendor signals, forbidding other indicators, which risks financial harm.

IMMEDIATELY execute a MARKET SELL to close all exposure.
Why it was refuted

The trading logic sits in a user-initiated prompt template for building a bot on the vendor's own signals. This is the declared product use, with no concealment or covert steering.

Supply chain

mediumRefutedlow confidence

The OpenAPI spec points the API gateway target at a raw-IP, plain-HTTP server (45.151.122.96:8011) instead of the HTTPS domain advertised in the description, so API keys and requests routed this way would travel unencrypted to an unnamed host; the spec openly explains this as a RapidAPI/Cloudflare workaround.

"url": "http://45.151.122.96:8011"
Why it was refuted

The raw-IP HTTP server entry is openly explained as the project's own RapidAPI gateway target. It is not hidden, and it is the same backend that serves the advertised service. The spec has no instruction directing an agent's credentials to an attacker. The MCP endpoint advertised in the description uses HTTPS. This is an insecure-transport design choice, not a supply-chain compromise.

Supply chain

mediumRefutedlow confidence

SKILL.md has the agent tell users to run an unpinned npx install of a third-party CLI, and to configure a local script (horus_mcp_public.py) that this skill does not ship.

`npx @smithery/cli install horus-flow-mcp`
Why it was refuted

The agent only relays an install command for the skill's own declared product to the user, who decides whether to run it. Promotional steering is covered by the separate SKILL.md finding.

Manipulation

mediumRefutedlow confidence

The landing page's free-plan handler shows a fabricated locally generated 'API key' and says it will be emailed, even though no key is issued server-side. This is an undeclared deceptive placeholder.

Key: horus-free-${Date.now().toString(36)}
Why it was refuted

This is a UI placeholder inside an unused free-plan handler, as its own comments show; the real signup flow is register.html. It is not a manipulation of an agent or any credential theft, and no chain to harm exists.

Coverage gaps 4

Parts of the artifact the static analysis could not fully examine.

unanalyzable_binary binary content is only byte-scanned
static/favicon.ico
unanalyzable_binary binary content is only byte-scanned
static/site/favicon.ico
skill_frontmatter_invalid missing name/description frontmatter
SKILL.md
frontmatter_unparseable no closed frontmatter block
SKILL.md