AxiomGate Open Security Teardown #01

GPT Researcher

Review date: 2026-09-13 Repository: https://github.com/assafelovic/gpt-researcher Reviewed snapshot: 6f998577d547b1e54ec662dac63583aa11e3b84b Snapshot commit date: 2026-08-23T22:16:37+03:00 Review mode: local, read-only, static analysis only Publication status: local report; no issue, comment, or social post was published

Formal outcome

AxiomGate Posture Score: NOT ASSESSED Grade: NOT ISSUED Reason: INSUFFICIENT COVERAGE — NOT ASSESSED

This is a deliberate fail-closed result. The requested package scope, gpt_researcher/, contains 127 files, including 124 Python files. AxiomGate completed the scan process, but recognized no framework or agents in that scope, leaving all 124 Python files outside adapter coverage. The scanner therefore withheld a numeric posture score. The result must not be converted into a passing or failing percentage.

The absence of a score does not mean the repository is safe. A separate read-only source review identified material architectural hardening gaps, documented below. It also does not prove exploitability: no target code, browser, subprocess, provider, external API, or LLM was executed or invoked.

Executive conclusion

GPT Researcher has a capable research orchestration pipeline: a GPTResearcher coordinator can select retrievers, fan out web and document work, optionally create nested research branches, collect MCP tools, and pass retrieved material into report-generation prompts. The repository’s own SECURITY.md accurately describes a trusted-operator deployment model and warns that the backend is not hardened for untrusted multi-tenant exposure.

The most important security boundary is therefore deployment-dependent. In a trusted local operator deployment, several behaviors are intentional configuration capabilities. In a shared or public deployment, the same capabilities become high-risk unless they are mediated by an explicit policy boundary. The code reviewed here does not visibly provide that policy broker.

The four principal findings are:

  1. High — MCP capability and side-effect policy is not enforced in the package. Request/configuration data can carry command, arguments, environment, remote URL, token, and tool metadata; tools are exposed to an LLM selector and then invoked with model-produced arguments. The repository documents this as operator-controlled, so this is a hardening finding rather than an unauthenticated RCE claim.
  2. High — External web and MCP material crosses into instruction-bearing LLM prompts without a visible trust boundary. Raw content is interpolated into report, summary, and curation prompts. This creates an indirect prompt-injection risk when retrieved content contains instructions aimed at the model.
  3. High — Egress and browser isolation are incomplete defense-in-depth. URL validation exists, but the code documents a DNS-rebinding time-of-check/time-of-use gap; browser navigation and redirects are not visibly revalidated; one loader disables TLS verification; the optional browser path enables JavaScript, imports browser cookies when configured, and uses a no-sandbox flag.
  4. Medium/High — Retrieval and scraping failures can be converted into plausible partial output. Broad exception handling, return_exceptions=True, empty-result fallbacks, unbounded browser scrolling, and a zero-delay default rate limiter make completeness and resource consumption difficult to prove at report boundary.

These findings should be treated as a constructive hardening program. They are not a claim that the maintainers intended unsafe behavior, nor a claim that a remote attacker can reach every path in a default deployment.

Method and evidence

Target acquisition

AxiomGate package scan

The requested scope was scanned with AxiomGate’s local research pipeline, JSON output, no database, and no target execution.

Check Observed result
Exit code 0
Scan ID scan-20260913182011441029
Tree SHA a22b9e672a0ac0f3
Governance result VERIFIED
Frameworks unknown
Agents 0
Tools 2
Edges 0
Raw findings 1
Finding AUTH-001, info, no agents discovered
Coverage 124 Python files had no adapter coverage
Posture INSUFFICIENT COVERAGE — NOT ASSESSED

AUTH-001 is interpreted as a coverage signal, not as proof that the package contains no agents. A source-level review shows orchestration classes and functions that the adapter did not recognize.

Supplementary whole-repository scan

A second scan covered the clone root only to understand architecture that is outside the requested package scope. It is explicitly supplementary and must not be presented as a complete assessment of gpt_researcher/.

Check Observed result
Exit code 0
Scan ID scan-20260913182045065658
Tree SHA 293e6279f3b2f9eb
Frameworks autogen, langgraph
Agents 20
Tools 8
Edges 14
Filtered findings 65
Coverage withheld: source syntax errors and incomplete linter coverage
Posture INSUFFICIENT COVERAGE — NOT ASSESSED

The supplementary graph includes optional multi_agents/ code, including LangGraph and AutoGen orchestrators. That directory is not the requested package and its findings are not used to claim that the core package is fully assessed.

Independent static inventory

A local AST inventory parsed the target Python files without importing or executing them:

The target source was never executed. The counts are structural observations only.

The separate AxiomGate linter completed with exit code 0 and emitted 0 findings for the requested package. Because the package scanner reported insufficient coverage, the linter’s empty result is not treated as a safety verdict.

Architecture and flow

The core flow observed in the target package is:

operator or API request
    -> GPTResearcher
       -> optional choose_agent LLM call
       -> ResearchConductor / DeepResearchSkill
       -> retriever factory and search/document retrievers
       -> optional MCP client and LLM tool selector
       -> browser or HTTP scraping backends
       -> compression and context joining
       -> report-generation and summary LLM prompts
       -> report output

The exact package does not contain a class literally named Lead Researcher. GPTResearcher and ResearchConductor perform the coordinating role. The optional multi_agents/ directory in the repository contains explicitly named researcher, reviewer, writer, publisher, and human nodes, but that is supplementary to this teardown’s requested scope.

MCP flow

The observed MCP path is:

mcp_configs
    -> convert_configs_to_langchain_format
    -> MultiServerMCPClient
    -> enumerate all tools
    -> LLM tool selection by index and description
    -> bind_tools
    -> tool.ainvoke/tool.invoke with model arguments
    -> permissive result normalization
    -> research context
    -> report prompt

Relevant evidence:

Web and report flow

Retrieved content follows this path:

search result or document
    -> raw_content / page_content
    -> context compression or direct context joining
    -> report, summary, or source-curation prompt
    -> model-generated report

Relevant evidence:

Deep-research fan-out

DeepResearchSkill creates nested GPTResearcher instances and runs branch tasks concurrently:

Findings

AG-TEARDOWN-01 — MCP capability boundary is not enforced

Severity: High Confidence: High for the design observation; exploitability is deployment-dependent.

The package accepts MCP configuration containing local command and arguments, environment variables, remote connection URLs, connection headers, tokens, and tool names. The configuration is translated into client configuration, every available tool is enumerated, and an LLM chooses tools by index and description before invocation. No visible package-level broker enforces an immutable server allowlist, tool-specific argument schema, side-effect class, approval requirement, or per-request capability attenuation.

This is a significant boundary when requests can be influenced by an untrusted user or when the service is shared. In the repository’s documented trusted-operator model, arbitrary MCP commands are an operator configuration feature. The evidence therefore supports a hardening request, not a claim of unauthenticated remote code execution.

Impact: A model or compromised/untrusted configuration path can obtain a capability broader than the research task requires. A tool may perform writes, network calls, secret-bearing requests, or local operations that are not visible in the research prompt.

Deterministic remediation:

  1. Introduce a policy broker between tool selection and invocation.
  2. Require a signed, immutable capability manifest for each server and tool. Bind the manifest to an exact server identity, not only a display name.
  3. Deny request-supplied stdio commands and environment values in shared deployments.
  4. Validate tool arguments against strict schemas, enforce byte/time limits, classify side effects, and require explicit approval for write-capable tools.
  5. Record the policy decision before invocation and fail closed when the server, tool, schema, or approval state is unknown.

Acceptance criteria: A test with a tool that attempts a write is denied without approval; a duplicate or out-of-manifest tool index is denied; a changed server identity is denied; all denied decisions are recorded without secrets.

AG-TEARDOWN-02 — Indirect prompt injection trust boundary is not visible

Severity: High Confidence: High for the data-flow observation; exploitability depends on retrieved content and model behavior.

Web pages, documents, and MCP results are treated as context and inserted into instruction-bearing model prompts. The reviewed code does not visibly attach a trusted/untrusted provenance label, delimit data from instructions with a policy-enforced message boundary, or validate tool output against a constrained result schema before the report model sees it.

An attacker who controls or edits a retrieved page can therefore place instructions in content that is later presented to the model. A model may follow those instructions, alter source selection, misstate evidence, or attempt tool use. No dynamic exploit was run, and this report does not assert that every model/provider configuration is exploitable.

Deterministic remediation:

  1. Represent external material as typed untrusted data with source, retrieval time, content hash, and a hard byte limit.
  2. Put data in a separate message/content part that the policy layer marks non-instructional; never interpolate it into system or developer instructions.
  3. Strip or neutralize active markup where it is not needed, while retaining a verifiable original hash.
  4. Make tool output schemas explicit and reject malformed or overlong output.
  5. Add adversarial fixtures containing instructions such as ignore previous rules and verify that the model cannot convert them into policy or tool commands.

Acceptance criteria: Retrieved text can contain model-directed instructions without changing the tool policy; the report records provenance and hash; malformed or oversized tool results fail closed; a test proves source content cannot create a new capability.

AG-TEARDOWN-03 — Egress and browser isolation are incomplete

Severity: High when the optional browser or permissive loader paths are enabled Confidence: High for the static observations.

The repository has a URL validator designed to reject private and special IP ranges, which is a useful control. Its own documentation states that validation followed by a separate HTTP client resolution leaves a DNS-rebinding time-of-check/time-of-use gap unless the resolved IP is pinned. The browser path can follow JavaScript and redirects without a visible per-hop revalidation. The WebBaseLoader path sets requests_kwargs verify=False and has a separate session.get path without a timeout. The optional Selenium path enables JavaScript, uses --no-sandbox and a remote debugging port on Linux, can import browser cookies when configured, and pickles cookies to a local file.

These are conditional paths: the default configuration sets SCRAPER to bs. They remain important because configuration can select the browser or loader backends.

Impact: A redirect or DNS race can move an otherwise permitted fetch into a private or special network range. Disabled TLS verification weakens server authentication. Browser cookies or a weakly isolated browser can turn a research fetch into a credential or host-boundary risk.

Deterministic remediation:

  1. Resolve and pin the permitted IP for the complete connection, and revalidate every redirect hop.
  2. Reject private, loopback, link-local, multicast, metadata, and other special ranges in production; do not expose a general opt-out in shared deployments.
  3. Enforce TLS verification and a timeout on every HTTP path.
  4. Remove browser-cookie import, remote debugging, and --no-sandbox from the production research path. Use a disposable, sandboxed browser profile if browser rendering is required.
  5. Bound navigation, redirects, JavaScript execution, scroll iterations, response bytes, and total wall time.

Acceptance criteria: A redirect to a private address is denied; a DNS rebinding test is denied or pinned safely; a certificate failure is denied; a browser job cannot read the operator profile; every fetch has a finite deadline and byte budget.

AG-TEARDOWN-04 — Partial failure and resource limits are not fail-closed at report boundary

Severity: Medium/High Confidence: High for the static observations.

The pipeline frequently treats failure as an empty or partial input. Examples include return_exceptions=True in gather calls, broad catches that continue, scrapers that return partial data, retrievers that return empty lists, and deep research that proceeds when at least one branch succeeds. Browser scrolling has no visible overall deadline or iteration cap. The default scraper worker count is 15 and the default rate-limit delay is 0, explicitly meaning no delay.

The result may look complete even though sources, branches, or tool calls were silently lost. The same fan-out behavior increases resource pressure under large source sets or adversarial pages. This is a robustness and availability concern; it is not by itself proof of an exploitable denial of service.

Deterministic remediation:

  1. Create one immutable budget object per request: wall time, pages, branches, response bytes, tool calls, and model context bytes.
  2. Propagate the budget through every retriever, browser, MCP call, gather, and report stage.
  3. Track each attempted unit as success, rejected, timed out, or failed.
  4. Return an explicit INCOMPLETE result when required coverage is missing; do not emit a normal report with silent omissions.
  5. Bound browser scrolling and cancel/await all created tasks.
  6. Set a positive default egress rate limit and make concurrency a policy value, not only a configuration value.

Acceptance criteria: A timed-out branch cannot produce a normal-complete report; the response includes deterministic completeness metadata; all child tasks are joined or cancelled; request limits are enforced even when Content-Length is absent.

Additional observations

These observations are not promoted to the four principal findings but should be considered in the hardening backlog:

OWASP GenAI mapping

The repository snapshot and the cited OWASP taxonomy use different numbering across versions. The labels below are intentionally precise:

Risk Current mapping Historical mapping Teardown evidence
Excessive agency / over-broad tools OWASP LLM06:2025, Excessive Agency OWASP LLM08:2023/24, Excessive Agency AG-TEARDOWN-01
Indirect prompt injection OWASP LLM01:2025, Prompt Injection, which includes indirect prompt injection OWASP LLM01:2023/24, Prompt Injection AG-TEARDOWN-02
Weak egress, browser and TLS controls Cross-cutting security control failure; assess with the relevant OWASP categories for the deployment Same AG-TEARDOWN-03
Silent partial work and uncontrolled consumption Relevant to robustness and unbounded resource use Same AG-TEARDOWN-04

The phrase LLM08 Indirect Prompt Injection combines two taxonomies. In the current 2025 list, LLM08 is Vector and Embedding Weaknesses; in the 2023/24 list, LLM08 is Excessive Agency. The prompt-injection finding is therefore mapped to LLM01, while the agency finding is mapped to current LLM06 and historical LLM08.

References:

EU AI Act Article 15 context

This is a technical mapping, not legal advice and not a determination that the repository is an EU AI Act high-risk system. Applicability depends on the provider, deployer, intended purpose, system classification, and use context.

Article 15 of Regulation (EU) 2024/1689 requires high-risk AI systems to be designed and developed to achieve appropriate levels of accuracy, robustness, and cybersecurity and to perform consistently in those respects throughout their lifecycle.

The observed controls map as follows:

Article 15 concern Static observation Required evidence or mitigation
Accuracy Source and branch failures can become empty or partial context without a report-boundary completeness state Coverage accounting, source provenance, explicit incomplete status, deterministic tests
Robustness Browser scrolling, fan-out, and task lifecycle are not bounded by one propagated budget Wall-time, byte, task, branch, and cancellation budgets with failure-state tests
Cybersecurity MCP capability, external content, egress, TLS, and browser boundaries are configuration-dependent and not visibly mediated by one policy broker Signed capabilities, pinned egress, strict TLS, sandboxing, data/instruction separation, tamper-evident audit
Lifecycle consistency Runtime package installation and broad environment/configuration overrides make the executable boundary mutable Pinned build artifacts, immutable configuration, dependency provenance, repeatable release tests

The appropriate conclusion is that an operator should collect deployment-specific evidence before making an Article 15 conformity statement. A static repository review cannot make that statement on its own.

Official legal text:

Prioritized remediation plan

P0 — Establish a capability and trust boundary

P1 — Make external content data, not instructions

P1 — Close egress and browser boundaries

P1 — Make completeness explicit

P2 — Harden the release boundary

Release recommendation

Recommendation: do not treat this teardown as a numeric pass/fail gate, because the requested package scan was not assessable.

Before any shared or public deployment, require the P0 boundary and the P1 egress, trust, and completeness controls, then rerun AxiomGate with an adapter or scan mode that demonstrably covers every target Python file. Until then, the repository’s trusted-operator/local deployment model should be treated as a hard boundary and enforced at the network and API layer.

Evidence retention

The raw artifacts behind this report were retained on operator-controlled storage outside the repository. They are not published here, and this section is retention rather than reproduction: nothing on this page can be re-derived from it.

They include the requested-scope scan JSON, supplementary root scan JSON, linter JSON, command logs, and the temporary clone path record, and are available on request. The target clone itself was removed after extraction. No target secrets were intentionally copied into the report or artifacts.