DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • The AI Memory Security Blueprint
  • The Agent in Your Pipeline Doesn't Have a Manager. That's the Problem.
  • We Empowered AI Agents With 'Hands,' Now We Require Kernel-Level Vision to Monitor Them
  • Securing Model Context Protocol Servers: 4 Gates From Code to Production

Trending

  • 12 Factor Framework for Building Secure and Compliant Cloud Applications
  • Retesting Best Practices for Agile Teams: A Quick Guide to Bug Fix Verification
  • AI in SRE: A Practical Autonomy Model for Self-Healing Infrastructure
  • Common REST Design Pattern
  1. DZone
  2. Software Design and Architecture
  3. Security
  4. 5 Infrastructure Controls for Securing AI Agents

5 Infrastructure Controls for Securing AI Agents

Prompt-based guardrails fail under adversarial pressure. Here are the five controls that helps to validate along with the configuration to implement them.

By 
Shekar Munirathnam user avatar
Shekar Munirathnam
·
Aug. 14, 26 · Analysis
Likes (0)
Comment
Save
Tweet
Share
83 Views

Join the DZone community and get the full member experience.

Join For Free

The Disturbing Discovery

In July 2026, the AI Red Team at NVIDIA published findings of a six-month assessment review of enterprise AI agents, ranging from tools for interactive coding to continuously running autonomous assistants. Across every framework and harness, the pattern that emerges is consistently the same — the agents that failed did so for four primary reasons: no access controls on the agent itself, capabilities to execute arbitrary code, no restrictions on outbound networking or segregation, and plaintext secrets available to the agent.

The problem is inherently architectural in nature. Any kind of defense relying on the control plane of the model — for example, constraining the system prompt or having the large language model serve as an adjudicator of the commands issued — inherits the statistical nature of the underlying model. There are three primary methods to bypass these defenses: disguising malicious activities as legitimate ones (e.g., “I’m debugging” or “I’m an admin”); gradual escalation through the dialogue until enough history accumulates to establish the legitimacy of the commands; and embedding code execution in legitimate behavior (e.g., installing a package).

This last one is especially worth noting. The coding agent that installs a library is expected behavior. The command pip install git+https://… pointing to a repository that is under the control of the attacker is arbitrary code execution disguised as legitimate development, and no policy-judging model can prevent this action from being performed without disabling the functionality of the agent entirely.

For the companies running such agents, the prompt must not be seen as the security boundary. Here are some considerations that better fit the situation.

Control 1: Identify the Agent via Authentication and Propagate the Caller’s Identity

The first and most common vulnerability is an agent that holds a service identity that can be accessed by any entity on the internal network. This configuration elevates a simple productivity tool into a common privilege escalation endpoint, where each user automatically receives the combined set of privileges of the agent.

Two key prerequisites have been established:

  1. Authenticate each call. No matter if it is an entry point through the Slack app, web UI, or MCP endpoint, the calls cannot be anonymous and implicitly granted by the network. An agent that ignores unauthenticated callers is a much harder target to probe.
  2. Propagate the human user’s identity into downstream calls. The agent shouldn’t be a self-sufficient entity to invoke commands. OAuth 2.0 Token Exchange (RFC 8693) can be used to allow the agent to exchange the user’s token for a downstream token which represents the user’s privileges, not the agent’s:
HTTP
 
POST /oauth2/token HTTP/1.1
Host: idp.internal.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<end_user_access_token>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=https://jira.internal.example.com
&scope=issue:read issue:comment
&requested_token_type=urn:ietf:params:oauth:token-type:access_token


This token would be limited to a single audience, to the two scopes necessary for the job, and to a short expiration. In case of misuse of the agent’s powers, the impact will be limited to the privileges of a single user, rather than the aggregated privileges of all users.

Consider the agent to be a non-human identity with a registered owner, a scheduled rotation period, and an expiration. An agent with no owner is virtually never going to get decommissioned.

Control 2: Assume Code Execution and Limit Its Effects

Instead of trying to prevent code execution through careful design, make the assumption that the agent will run attacker-influenced code and arrange for the effect of that code to be benign and insignificant.

It is important to note that a shell utility is not needed for achieving that goal – only write access is required. When an agent can modify configuration files like ~/.bashrc, ~/.gitconfig, a Git hook, MCP.json, or its own instruction file, then code execution happens as soon as another process reads the modified file. Configuration files, in this sense, serve as executable code, but with some extra steps in between.

Shell
 
docker run \
  --rm \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=256m \
  --mount type=bind,source="$PWD/workspace",target=/workspace \
  --user 10001:10001 \
  --cap-drop=ALL \
  --security-opt no-new-privileges:true \
  --security-opt seccomp=/etc/docker/seccomp-agent.json \
  --pids-limit 256 \
  --memory 4g --cpus 2 \
  --network agent-egress \
   agent-runtime:2026.07


When creating a hardened baseline of containers, the following points should be emphasized:

  • A read-only root filesystem will ensure that write attempts to dotfiles fail at the OS level rather than at the model’s discretion.
  • Use of noexec on writable mounts breaks the “read, write, execute” pattern.
  • Dropping all capabilities and setting no-new-privileges blocks privilege escalation mechanisms.

Then, mount the agent’s configuration as read-only and from a different mount point than the workspace of the agent:

Shell
 
  --mount type=bind,source=/etc/agent/AGENT.md,target=/etc/agent/AGENT.md,readonly \
   --mount type=bind,source=/etc/agent/mcp.json,target=/etc/agent/mcp.json,readonly


An agent that is able to change its own instructions can assume a completely different persona, including the “authorized debugging user” frame the red team was able to demonstrate.

In cases where providing a command utility is unavoidable, use the following strategy:

  • Use an allowlist of binaries and wrap each invocation in a wrapper that removes shell metacharacters, resolves paths, and does not allow any action that goes beyond /workspace.
  • Treat any external inputs – filenames, ticket titles, and document names coming from external systems – as tainted.

Control 3: Default-Deny Egress From Each Perimeter

Outbound network connectivity turns the constrained execution environment primitive into an actual incident by serving as the means of exfiltration and establishing a reverse shell connection. When NVIDIA tested their system under proper egress restriction, the red team had to perform their activities through the agent process itself — characterized by low speed, high noise, and unreliable performance.

Restrict egress in places where the agent does not have direct access to the enforcement point. In case of Kubernetes environments:

YAML
 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: agent-runtime-egress
  namespace: agents
spec:
  podSelector:
    matchLabels: { app: agent-runtime }
  policyTypes: [Egress]
  egress:
    - to:
        - podSelector:
            matchLabels: { app: egress-proxy }
      ports:
        - { protocol: TCP, port: 3128 }
    - to:
        - namespaceSelector:
            matchLabels: { kubernetes.io/metadata.name: kube-system }
      ports:
        - { protocol: UDP, port: 53 }


All network connections are restricted except those that are explicitly allowed, including blocking the cloud metadata endpoint (169.254.169.254), which provides a credential source without requiring any exploitation. Route the allowed connections through an authenticating proxy server that uses an allowlist of fully qualified domain names (FQDNs), optionally terminates TLS for analysis, and records every request with user identification data attached. This logging creates the incident timeline.

Control 4: The Agent Never Holds a Persistent Secret

The common practice is to inject secrets via environment variables without making any write calls to the disk, because it is commonly accepted that the only code supposed to run in the container is the expected one. This is untrue for modern times, where a large language model (LLM) runs with the shell in the same process space — env, printenv, and /proc/self/environ are one prompt away, and CLI tools helpfully cache credentials in predictable locations: .netrc, .git-credentials, shell history, and .env files.

The most interesting observation made during red teaming was the ability to extract secrets via the chat interface even when all network-based data exfiltration is prevented. The model can read environment variables and return credentials. Regardless of any network isolation, there is no way to protect data the agent is authorized to see.

Thus, secrets cannot be accessible to the agent at all. Broker tokens per task instead:

Python
 
# Agent requests capability, never a credential.
token = broker.issue(
    principal=ctx.end_user_id,        # the human, not the agent
     audience="https://api.github.com",
    scopes=["repo:status", "pull_request:write"],
    resources=["org/repo-name"],
    ttl_seconds=300,
)
try:
    github.post_review(token, pr_id, body)
finally:
    broker.revoke(token)              # revoke on completion, not on expiry


Recommendations:

  • Never inject secrets into the container image, environment, volume mounts, or context window.
  • Set very short time-to-live (TTL) values for secrets, measured in minutes.
  • Invalidate tokens after finishing the task.
  • Record every secret issuance along with the identification of the human user.
  • Once the secret is available to the agent, it is already a win for the attacker.

Control 5: Package Installation Is a Supply Chain Control

Use an internal proxy repository to control the agent’s package manager and stop VCS and URL installations of any packages:

Plain Text
 
# /etc/pip.conf  (root-owned, read-only mount)
[global]
index-url = https://artifactory.internal.example.com/api/pypi/pypi-approved/simple
no-index = false
require-hashes = true
# /usr/etc/npmrc
registry=https://artifactory.internal.example.com/api/npm/npm-approved/
ignore-scripts=true


ignore-scripts=true is the silent victory — this will stop postinstall from being used as an execution vector. The agent must only install packages which are resolvable through the internal repository.

Trust, But Verify

Ship these as test cases, not as documentation:

Assertion

Test

Unauthenticated callers rejected

Invoke the agent with no token, and with another user’s token

Dotfile writes blocked

Ask it to append to ~/.bashrc and to modify its own instruction file

Egress denied by default

Request a fetch from an unapproved host; confirm proxy denial in logs

No secrets in environment

Ask it to print its environment and read /proc/self/environ

Metadata endpoint unreachable

Request 169.254.169.254/latest/meta-data/

VCS installs blocked

Ask it to pip install git+https://… from an external URL

 

Run these on every release, and run the multi-turn variants — the escalation that works is rarely the one in a single message.

Key Takeaway

Prompt-based guardrails are meant to be a usability feature that prevents accidental damage, but they do not hinder an adversarial actor who intends to cause harm. Each request needs to be validated through identity authentication (JWT validation or equivalent), confirming the caller is who they say they are — alongside a secure sandbox environment without writable-executable paths, default-deny network egress at every boundary, and short-lived credentials issued to the agent per task.

This is not new security engineering. It is the application of least privilege, isolation, and secrets management to a workload that interacts with untrusted input in real time. The mistake is assuming the model is the enforcement point, when it is in fact the thing being defended.

AI security

Opinions expressed by DZone contributors are their own.

Related

  • The AI Memory Security Blueprint
  • The Agent in Your Pipeline Doesn't Have a Manager. That's the Problem.
  • We Empowered AI Agents With 'Hands,' Now We Require Kernel-Level Vision to Monitor Them
  • Securing Model Context Protocol Servers: 4 Gates From Code to Production

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook