Securing MCP beyond the gateway: InfoQ's four control layers, decoded

A decode of InfoQ's four-layer MCP security model (CI exec gates, isolated tooling, egress limits, manifest pinning) for teams running MCP servers.

Picture a platform engineer at a 40-person SaaS company who has wired four MCP servers into an internal ops agent: GitHub, Postgres, a homegrown web-fetch tool, and a third-party server someone on the team found and liked. She put a gateway with OAuth in front of all of it, wrote the audit logs to the SIEM and moved on. The gateway does its job. It knows who called which tool. It does not notice when the web-fetch tool is handed a URL pointing at an internal service, or when the third-party server quietly rewrites a tool description three weeks after she approved it. It also doesn't cover the MCP inspector she left running on the office network last sprint.

That gap is the subject of Securing MCP in Production: Defense-in-Depth beyond the Gateway, published by InfoQ on July 29, 2026. @bibryam's post credits it to Nik Kale and boils it down to CI gates for tool execution, isolated tooling with scoped tokens, and diff-based manifest reviews. The author's argument is that a gateway is one enforcement point, not a control plane.

What it is

The article isn't a product. It's an architecture write-up from a team that, the author says, chose MCP as the integration layer for a production multi-agent platform at the end of 2025. It splits MCP security into four layers, each with its own "earliest trustworthy enforcement point." The author says every pattern works with the current MCP spec and needs no protocol changes. Mapped to the lede:

The author says the gateway takes part in only two of the four layers, and only partially.

Alternatives and complements named in the sources:

Who it's for

Pick this up if you run MCP servers that hold real credentials or reach real networks: cloud identities, internal APIs, databases, anything an SSRF could reach. It also fits if you install third-party servers that can update after you approve them, or if your team already has a gateway and is wondering what it misses. The four-row matrix in the article works as a review checklist.

Skip it, for now, if you run a couple of local stdio servers on your own laptop with no secrets beyond your own environment. Scalar notes that MCP authorization applies to HTTP transports and that stdio servers should read credentials from the environment instead. Layer 1 hygiene still applies to code you write, but egress allow-lists and behavioral baselines are overhead you probably won't recoup.

Before and after

Before:

  1. Approve a server once, at install.
  2. Put a gateway in front for authentication and audit.
  3. Give the server whatever cloud identity makes it work.
  4. Leave the inspector and test harness on their defaults.
  5. Find out about a changed tool definition when something breaks.

After, following the article:

  1. A Semgrep rule in CI blocks builds where a handler parameter reaches a shell or eval.
  2. Every management endpoint requires authentication, and dev tooling sits on an isolated network.
  3. Each server gets a network egress allow-list and a token scoped to one purpose.
  4. Tool manifests are hashed at registration. Any change produces a diff someone reviews before the agent loads it.
  5. The gateway keeps doing authentication, authorization and audit.

For step 3, the authorization sources fill in the token side. Scalekit's guide to the 2026-07-28 spec says a server should accept only tokens issued for its own URL and never pass a client's token through to upstream APIs. Maxim points out that spec scopes are server-defined strings and the spec does not define which caller may run which tool.

Try it

The smallest real step is the article's execution fix and CI rule. Here is the vulnerable pattern and its fix, as the article shows them:

// VULNERABLE: string interpolation into a shell command
const { username } = toolCall.params;
exec(`docker run maigret ${username}`);
// If username is "; rm -rf /" the shell interprets the semicolon.

// FIXED: array-based argument passing, no shell interpretation
const { username } = toolCall.params;
execFile('docker', ['run', 'maigret', username]);
// Semicolons and metacharacters are passed as literal values.

And the Semgrep rule the author uses to block builds:

rules:
  - id: mcp-unsafe-exec-js
    languages: [javascript, typescript]
    severity: ERROR
    message: >
      MCP tool handler passes a parameter into a shell interpreter.
      Use execFile or spawn with array arguments instead.
    pattern-either:
      - pattern: exec(`...${$PARAM}...`)
      - pattern: exec($CMD + $PARAM)
      - pattern: eval($PARAM)
  - id: mcp-unsafe-exec-py
    languages: [python]
    severity: ERROR
    pattern-either:
      - pattern: subprocess.run(..., shell=True, ...)
      - pattern: os.system($CMD)
      - pattern: eval($PARAM)

The article doesn't give Semgrep install or CI wiring steps, versions or prerequisites, so plug it into whatever runner you already use. The author calls these rules a starting point that catches common sinks, not full production coverage.

For layer 4, DEV Community describes a staging test you can run today. Approve a clean test tool, record which tools your agent calls and with what arguments, then swap in a poisoned definition under the same name. Check whether the agent's behavior changes and whether anything in your pipeline flags the change. The post names mcp-scan but gives no install command. None of the sources discuss cost for any of this.

Where it breaks

Sources