Open a GitHub issue with the label security, or email the address on
the maintainer's GitHub profile if the details should stay private
until fixed. Reports that include a runnable reproduction get fixed
fastest. Please state the attacker position your finding assumes (see
the threat model below): a report whose precondition is already
arbitrary local write access to the user's files will be assessed
against that boundary.
world-intel-mcp is a single-user, local tool. It runs as an MCP stdio server, a CLI, a local dashboard, or a local collector daemon, under one user account, on that user's machine. It aggregates free public OSINT feeds. Its trust boundaries:
-
Upstream data is untrusted and unauthenticated by design. The server aggregates public APIs and RSS feeds (USGS, GDELT, adsb.lol, NASA FIRMS, and about 115 others). None of these are signed. The server preserves provenance (
sourcelabels, per-feed propaganda risk tiers,_stalemarkers,data_gaps,citedflags) so a consumer can judge the data; it cannot make public data trustworthy. Analysis outputs are derived from these inputs and inherit their trust level. Treat every output as open-source intelligence, not as verified ground truth. -
The local machine is inside the trust boundary. The SQLite cache, the AOI store, and the optional Qdrant vector store live on the user's own machine and are trusted by the process that wrote them. An attacker who can already write the user's files or reach the user's local services can feed the server false data; that same position also allows patching this package's code, so in-database integrity signing would not remove the attack, only relocate it. Hardening applied at this boundary: the cache database is created with owner-only permissions (0600), all SQL is parameterized, and the codebase contains no shell execution, no
eval/exec, and no deserialization of non-JSON formats. -
MCP tool arguments are untrusted input. Arguments are validated (ranges, types) where they parameterize queries, are never interpolated into SQL (parameterized statements only), never reach a shell (no subprocess usage exists in the package), and never select filesystem paths (report output paths are server-generated, not caller-supplied).
-
Optional local services are the operator's responsibility. Qdrant (vector search) and Ollama (brief generation) are reached at
localhostURLs. Bind them to loopback, as their defaults do; if you expose them on a network, that exposure is outside this project's control. Do not pointOLLAMA_API_URLat an untrusted host: its responses are rendered in briefs. -
Stale data is a feature with a marker, not a hidden fallback. When an upstream fails, the fetcher may serve expired cache entries so dashboards do not go blank. Such responses carry
_stale: true, and circuit-breaker state is visible viaintel_status. Consumers that must not act on stale data must check the marker.
Only the latest release receives fixes.
- Findings that assume arbitrary local file write, code execution, or root on the user's machine (boundary 2 above).
- The authenticity of upstream public OSINT data (boundary 1).
- The network exposure of separately installed services (boundary 4).
- No cryptographic integrity protection on the cache or vector store; see boundary 2 for why that is not the chosen control.
- Dependency supply chain is managed by pinning and review, not by
vendoring;
pip installtrust applies. - The dashboard binds locally and has no authentication; do not reverse-proxy it to an untrusted network.