Aug 1, 2026·6 min read·6 visits
A path traversal vulnerability in gemini-bridge allows attackers to read arbitrary local files by exploiting improper canonicalization and a missing validation check in the server's inline payload preprocessor.
Between versions 1.0.0 and 1.3.1, the gemini-bridge Model Context Protocol (MCP) server failed to restrict candidate file paths to the workspace root when processing files in inline mode. This allowed unauthenticated local users, or remote attackers executing prompt-injection payloads against connected AI agents, to traverse the directory tree and read arbitrary system files. The retrieved contents were subsequently forwarded to the external Gemini AI CLI and returned in the round-trip response.
The gemini-bridge package is an integration framework designed to connect Model Context Protocol (MCP) clients, such as Claude Code, with Google's Gemini AI engine via the official CLI tool. To enrich prompt contexts, the server exposes the consult_gemini_with_files tool, allowing client agents to attach specific workspace files to their outgoing queries. This establishes a high-trust attack surface, as the server must strictly regulate the directory paths it accesses to prevent unauthorized file extraction.
Historically, the server operated under the assumption that path resolution logic would confine the candidate file paths to a specified, secure working directory. However, the path translation workflow in inline mode did not implement adequate checks, enabling arbitrary absolute or relative paths to bypass restriction boundaries. As a result, the tool could be coerced into reading sensitive system configuration files, credentials, or private workspace assets.
Once read, the file contents were seamlessly attached to the outgoing query structure and processed by the LLM CLI. Because the client controls both the target path and the command prompt, an attacker can instruct the model to echo the loaded file verbatim, bypassing typical boundary barriers. This transforms a simple traversal issue into a full disclosure pipeline.
The root cause of this vulnerability lies in two distinct flaws in src/mcp_server.py. The first flaw is the absence of canonicalization within the _resolve_path function. The function did not utilize Python's Path.resolve() method, which meant that symbolic links, Windows 8.3 short names, and relative path traversals (e.g., ../) were not expanded to their absolute real paths prior to validation.
def _resolve_path(directory: str, candidate: str) -> tuple[str, str | None]:
candidate_path = Path(candidate)
abs_path = (
str(candidate_path)
if candidate_path.is_absolute()
else str(Path(directory) / candidate)
)
try:
# Fails to resolve canonical paths before computing relative relation
rel_path = os.path.relpath(abs_path, directory)
except ValueError:
rel_path = None
if rel_path and rel_path.startswith(".."):
rel_path = None
return abs_path, rel_pathThe second, more critical flaw resides in how the _prepare_inline_payload function processed the outputs returned by _resolve_path. When a traversal path or an absolute path escaping the root directory was parsed, _resolve_path correctly detected that the path escaped the root and returned rel_path = None.
However, the calling loop in _prepare_inline_payload did not verify whether rel_path was None. Instead of skipping the file, it executed a fallback option display_name = rel_path or Path(abs_path).name and then directly loaded the file from the unconfined abs_path variable. This allowed any arbitrary file path to pass through the validation check and be read.
The vulnerability was mitigated in version 1.3.1 (Commit 8f3b85afd02b692c4bc974b5176e12fb277ea801). The patch introduces strict canonicalization via Python's Path.resolve() and adds explicit condition checks to the inline payload processing logic.
In the patched implementation, both the workspace root and the target candidate paths are fully resolved to strip out traversals and symbolic link tricks. This canonicalized target is then verified against the canonicalized root directory using abs_path.relative_to(root):
# Annotated Patch Changes in src/mcp_server.py
def _resolve_path(directory: str, candidate: str) -> tuple[str, str | None]:
# Resolve the working directory root and any symbolic links
root = Path(directory).resolve()
candidate_path = Path(candidate)
# Compute and resolve the absolute candidate path
abs_path = (
candidate_path if candidate_path.is_absolute() else root / candidate
).resolve()
try:
# Ensure candidate strictly resides under root using relative_to
rel_path = str(abs_path.relative_to(root))
except ValueError:
# Throws ValueError if candidate is outside root boundaries
rel_path = None
return str(abs_path), rel_pathAdditionally, the patch enforces the path traversal boundary check in the calling loop of _prepare_inline_payload:
for original_path in files:
abs_path, rel_path = _resolve_path(directory, original_path)
# If rel_path is None, the path escaped the root. The file is skipped.
if rel_path is None:
warnings.append(
f"Skipped file outside working directory: {original_path}",
)
continue
display_name = rel_pathThis combined patch ensures that unconfined file paths are discarded before any filesystem reads can occur, effectively mitigating the arbitrary read vector.
An attacker can exploit this vulnerability through local command execution or indirect prompt injection vectors. The primary prerequisite is that the gemini-bridge service must be active and listening for tool calls, which is typical when integrated with an automated agent workflow.
In a direct exploitation scenario, the user or local system components make a direct tool call to the MCP server. By supplying a directory value and an out-of-bounds target file path, they can force the server to load arbitrary files:
{
"method": "tools/call",
"params": {
"name": "consult_gemini_with_files",
"arguments": {
"query": "Please summarize this file verbatim:",
"directory": "/home/user/workspace",
"files": ["../../../../etc/passwd"],
"mode": "inline"
}
}
}In an indirect prompt injection attack, a remote attacker can structure an injection payload (e.g., in a public Git repository description or an issue comment) that trick the client AI agent. When the agent processes the injection, it is instructed to invoke consult_gemini_with_files with malicious parameters, silently exfiltrating targeted system files such as SSH keys or .env credential files.
The confidentiality impact of this vulnerability is high. Because the application runs with the privileges of the local system user running the MCP server, any file readable by that user's shell can be retrieved. This exposes sensitive items such as SSH private keys, environment variables containing API keys, local databases, and configuration settings.
The CVSS v3.1 score is evaluated at 6.2 (Medium), with the vector CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N. While classified as a local attack vector (AV:L), the emergence of indirect prompt injection vectors against AI agents allows remote actors to trigger the exploit sequence without possessing direct local console access.
No active exploitation in the wild has been observed, nor has this CVE been listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, due to the ease of automated exploitation of prompt-injection targets, instances utilizing unpatched server versions face elevated risk.
The primary remediation for this vulnerability is to upgrade the gemini-bridge package to version 1.3.1 or higher. This release integrates the necessary code-level path validation and canonicalization patches to successfully neutralize directory traversals.
For deployments where immediate updates are not feasible, you can apply temporary mitigations. Restricting write access to the workspace directory prevents attackers from writing symbolic links pointing to sensitive system files. Furthermore, you should deploy the server inside a containerized sandbox or under a restricted user account with minimal filesystem privileges.
Finally, because the tool interface allows specifying the directory argument dynamically, developers should modify client-side integrations to enforce hardcoded, system-defined root paths. This ensures that the agent cannot be tricked into redefining the root workspace to a broader path (like / or C:\) during runtime.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
gemini-bridge eLyiN | >= 1.0.0, < 1.3.1 | 1.3.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Secondary CWE ID | CWE-200 |
| Attack Vector | Local |
| CVSS v3.1 Score | 6.2 |
| Exploit Maturity | Proof-of-Concept (PoC) |
| CISA KEV Status | Not Listed |
| Ransomware Use | No |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located within a restricted directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location outside of the restricted directory.
An open redirect vulnerability exists in core-geonetwork from versions 3.12.0 until 4.2.16 and 4.4.11 due to unsafe redirect validation in GeonetworkOAuth2LoginAuthenticationFilter and KeycloakAuthenticationProcessingFilter. An attacker can construct a protocol-relative URL to bypass local redirection checks and redirect authenticated users to malicious external domains.
An observable response discrepancy vulnerability in WPGraphQL versions 2.0.0 through 2.15.0 allows unauthenticated remote attackers to enumerate users and extract public profile metadata. Although the password reset mutation is designed to return a uniform success response to prevent enumeration, a legacy deprecated field resolver bypasses this mechanism by resolving the associated user profile if the target account exists.
FileBrowser Quantum (a fork of Filebrowser) prior to version 1.4.3-beta is vulnerable to multiple directory traversal flaws in its subtitle handler endpoint (`GET /api/media/subtitles`). This allows authenticated users with standard access to read arbitrary text files on the host system.
A security vulnerability in sigstore-go prior to version 1.2.1 allowed the use of expired or retired self-managed long-lived public keys wrapped in an ExpiringKey configuration to successfully sign code or artifacts. Because the verification pipeline verified the cryptographic signatures and RFC 3161 timestamps but failed to perform a temporal boundary check on the public key's validity window, verifiers running affected versions would mistakenly accept signatures produced outside of the key's designated operational lifetime.
Improper input validation of the supiOrSuci field in free5GC Authentication Server Function (AUSF) allows unauthenticated remote attackers to trigger an unhandled parsing exception, resulting in a Denial of Service (DoS) and internal stack trace exposure.
The zaino-state crate contains two critical flaws in its block reorganization and state synchronization logic. An unbounded recursive async function handling block reorganization fails to validate cyclic relationships, enabling network peers to cause infinite loops that exhaust CPU and memory resources. Furthermore, a logical pruning error during non-finalized block cache trimming can purge all cached blocks, triggering an immediate panic and crash of the daemon.