Securing AI Agents on AWS: One HTTP Tool, One Action Gateway
Yuri Shapira, Co-founder and CTO
Why Cynative gives security agents one HTTP tool, uses AWS-maintained models to follow API changes, and checks IAM actions before signing requests.
While developing Google Kubernetes Engine (GKE) support for Cynative, we tested the CLI against a real cluster with auto-approval enabled. The agent returned a list of Kubernetes namespaces. In the summary below the list, it also mentioned that it had enabled the cluster's DNS-based endpoint to get access.
At the time, our connector did not support access through GKE's external IP endpoint. GKE offers DNS-based access as another way to reach its control plane.1 The agent enabled that option and continued. A limitation in our implementation had become a configuration change in the environment we were supposed to inspect.
There was no prompt injection. The agent was pursuing the investigation and reported the change after making it. What it treated as a practical workaround was a decision our security tool should have left to the operator.
That test made the action gateway a requirement for the CLI. We needed the system to enforce the difference between inspecting infrastructure and changing it, even when the change helped the investigation succeed.
Cynative is an open-source framework and CLI for security agents that investigate code, cloud infrastructure, and running workloads. The agent writes research code in a sandbox and queries connected services through the host application, using credentials the operator already has.2
We wanted that agent to follow an investigation wherever the evidence led, without inheriting every permission those credentials carried. The resulting architecture combines two decisions: one generic HTTP tool for API access, and a gateway that interprets each request before authorizing it. This post follows the AWS implementation, where service models and permission mappings let that small interface keep up with a much larger platform.345
Why HTTP, rather than a tool for every operation?
A security investigation rarely follows a fixed sequence of API calls. It might start with a storage bucket, lead to an application's execution role, and end in the repository that deploys it. A useful agent needs to ask the next question, not just the questions its tool author anticipated.
Typed, operation-specific tools are attractive for a bounded workflow. They provide argument validation, documentation, and convenient defaults. But a wrapper also becomes another API surface to maintain. A new operation needs a new tool; a new parameter needs a schema update; an omitted response field may require changing the wrapper before the agent can use it. Generating wrappers reduces the manual work, but still leaves a generated catalog to refresh and distribute.
Cynative instead exposes one universal API-access tool: http_request. The agent supplies the method, URL, headers, body, and connector-specific authentication context. The host handles credentials. The same tool serves the supported cloud, code-hosting, and Kubernetes connectors; separate tools handle research code and orchestration. We do not need a different model-facing function for each AWS operation.3
This preserves the provider's native interface. A new filter can be expressed in the request, and a newly returned field can be read from the response, without adding either to a Cynative wrapper. The agent can also compose requests in sandboxed JavaScript: follow pagination, query several resources, correlate results, and return a summary rather than moving every intermediate response through another model turn. The API-access implementation stays generic while the investigation code adapts to the question.3
The popularity of the supported platforms helps. Modern models often know their APIs surprisingly well, drawing on familiar request patterns and consulting documentation when needed. Cloudflare's Code Mode describes a related observation: models can work effectively with native programming interfaces and compose calls in code, rather than navigating an ever-growing set of specialized tools.6
Let frequent changes arrive as data
A small tool interface would buy little if every new AWS operation still required a handwritten gateway rule. The authorization layer has to follow the same design: interpret provider-maintained definitions instead of rebuilding the service catalog in our code.
AWS describes more than 200 services and an agent-facing surface of over 15,000 APIs. Cynative's AWS classifier works at a different level: six wire-protocol variants across the JSON, Query, and REST families, with one request-signing path, SigV4. We maintain those shared mechanisms instead of a wrapper for every operation.789
Those layers also change at different rates. AWS publishes API model updates daily. The JSON, Query, and REST families already appeared in Botocore's 2016 implementation, and AWS dates SigV4's introduction to 2012. Their longevity is why we would rather maintain protocol interpreters than track each service's release schedule.101112
This makes API growth a data-update problem rather than a tool-release problem. When a new operation uses the supported protocols, SigV4 authentication, endpoint conventions, and metadata formats, Cynative can pick it up after a metadata refresh. Its permissions go through the same resolution and policy checks as any other request. Code changes are needed when those shared contracts change, rather than every time AWS adds an operation.5813
The engineering work moves from maintaining individual wrappers to interpreting and authorizing native requests.
A flexible interface is not a permission grant
Consider two Secrets Manager operations. DescribeSecret returns configuration metadata; GetSecretValue returns the secret itself. Both use POST / on the same endpoint. AWS's SecurityAudit policy permits the first and omits the second. Neither the HTTP verb nor a generic "read-only" label captures the distinction an audit needs.1415
An approval prompt cannot reliably supply that distinction either. Auto-approval removed the human checkpoint in our GKE test. Keeping it would have given us a chance to catch the change, but only if someone recognized the risk in a stream of tool calls. Operators can approve mechanically, especially when a change appears to help the investigation continue. Research on security warnings documents the related problem of habituation.16
Cynative also includes prompt-injection protections. External tool results are fenced as untrusted data, tagged with their producing tool, and escaped so embedded closing delimiters do not terminate the fence. The system prompt explicitly tells the model to analyze that content, not obey its instructions. Sub-agent summaries receive the same untrusted framing because they can carry instructions encountered during a delegated investigation.17
These controls address hostile instructions in the data an agent reads. Our GKE test exposed a different problem: an agent can exceed its intended role while pursuing a legitimate task. The same permission boundary needs to hold in both cases, regardless of why the model chose the request.
The action gateway sits outside the model. Sandboxed research code has no independent host or network access, and the host application holds the credentials. Every API request goes through that application. Human approval remains an additional checkpoint; enabling auto-approval does not bypass the gateway.2184
Following a request from HTTP to IAM
On AWS, Cynative uses the SDK's credential discovery, including profiles, SSO-backed sessions, environment credentials, and workload roles. It selects SecurityAudit as the default action policy. The launching identity needs permission to retrieve that policy and run IAM policy simulation, but the local check does not require a new Cynative-specific role.1920
The next problem is translating the agent's request into something that policy can evaluate. An SDK normally translates an operation into HTTP. The gateway works backward: HTTP to operation, operation to IAM actions, then actions to a policy verdict. Our approach was heavily informed by iann0036/iamlive, whose proxy mode maps AWS traffic to IAM permissions for policy generation. Cynative performs the translation before sending the target request.21
Agent or sandboxed research code → model-authored HTTP request ↓
- 01 Validate destination and request authority Rejected → tool error
- 02 Identify AWS operation AWS API Models · unrecognized → tool error
- 03 Resolve required IAM actions Service Reference, iam-dataset · unresolved → tool error
- 04 Evaluate actions against session policy Policy document, SimulateCustomPolicy · denial or evaluation error → tool error
- 05 Attach SigV4 authentication Harness-held AWS credentials
↓ Signed request sent to AWS. Every tool error returns to the agent.
Policy loading and simulation use separate authenticated control calls. The target request is signed only after its IAM actions pass the policy check.20
First, establish what will actually be sent
For our Secrets Manager example, the request looks like this:
POST / HTTP/1.1 Host: secretsmanager.us-east-1.amazonaws.com Content-Type: application/x-amz-json-1.1 X-Amz-Target: secretsmanager.DescribeSecret {"SecretId":"example/database"}
The transport constructs the request before classification and derives Host from the URL. The gateway therefore checks the same method, path, headers, query, and body that the transport will send, rather than an operation name supplied alongside a potentially different request.4
Destination checks require HTTPS and a supported AWS endpoint, then reconcile the hostname with the service and region claimed by the agent. Claiming to call Secrets Manager does not authorize sending credentials to an arbitrary host. Model-supplied authentication headers and credentials embedded in URLs are rejected before signing.49
AWS API Models identify the operation
The first source of service knowledge is AWS's published Smithy models. AWS maintains these definitions to describe its APIs, including operations, protocols, routes, and request bindings. Cynative retrieves the model archive, discovers service definitions, selects the latest available model version for each service directory, and builds an index by endpoint prefix. The service list is discovered from the archive, not maintained as a list of tools.105
For our request, the AWS JSON classifier extracts DescribeSecret from X-Amz-Target and checks that the operation exists in the service model. AWS Query and EC2 Query identify operations through Action in a POST form body or GET query string; missing, duplicate, and unknown action names are rejected. REST-JSON and REST-XML instead require matching the HTTP method and URI template, with modeled query and header discriminators helping distinguish routes.2223
This is where the maintenance argument becomes concrete. A newly published operation shape can be loaded and handled by an existing protocol classifier. We update the data describing the service rather than write another service-specific function.58
AWS Service Reference connects operations to permissions
Identifying the operation is not enough, because API names and IAM action names are not interchangeable. For a general-purpose S3 bucket, ListObjectsV2 requires s3:ListBucket. Other operations can require several actions.24
Cynative's primary mapping source is AWS Service Reference. Its Operations[].AuthorizedActions entries connect API operations to IAM permissions, yielding secretsmanager:DescribeSecret in our example. This is another AWS-maintained input: as AWS publishes mappings, the gateway can consume them without a new per-operation rule.25
When Service Reference has no usable action set, Cynative consults the community-maintained iam-dataset. A final fallback infers namespace:Operation from the name, except where namespace sharing makes that inference unsafe. The resolver takes the first usable source. AWS documents gaps in its operation mappings and excludes downstream permissions needed through Forward Access Sessions from that dataset.252613
Unclassifiable or unresolved requests are rejected. When multiple service models match, the gateway requires the union of their resolved actions. The explicit permissionless exception is sts:GetCallerIdentity, which AWS documents as requiring no permission. It still passes destination checks; credential-issuing STS calls do not receive the exception.1327
The selected policy decides whether to sign
The third AWS-maintained input is the default policy itself. SecurityAudit is a job-function policy for inspecting security configuration, not our own catalog of "safe reads." It supplies the distinction between describing a secret and retrieving its value. As AWS updates the policy, a subsequent policy load can pick up those changes without a Cynative release.2815
Cynative retrieves the selected policy's current default version with GetPolicy and GetPolicyVersion. For each uncached action, it calls SimulateCustomPolicy with the policy document and action name. Only allowed passes. Denials, empty results, and API failures block the target request. An in-memory cache keyed by policy version and action avoids repeating the IAM round trip.20
Our DescribeSecret request passes under the default policy. Changing its target to GetSecretValue produces a different IAM action and a denial before signing. The model receives an error identifying the required actions and policy ARN; sandboxed code can catch the rejection. An explanation can help the agent continue within scope, but it cannot grant the missing permission.141529
Only allowed requests receive SigV4 authentication and leave the client. Automatic redirects are disabled, so another destination requires another request through the same checks.4
What happens when AWS adds the next operation?
The path stays the same. Updated models describe the request, updated mappings identify its permissions, and the selected policy decides whether those actions belong in the investigation. Recognizing a new API does not automatically authorize it. The interface and the policy remain separate even as both evolve.51320
Metadata has a default 24-hour disk-cache lifetime. Availability also depends on upstream publication: AWS documents up to 24 hours of delay for Service Reference changes.3025
Choose the session's scope, then enforce it
SecurityAudit defines an audit job's scope. That includes sensitive metadata and audit-support operations such as generating a credential report. Remediation can require a different scope, and the operator can choose it for a single session without changing the CLI's default.1519
For example, an operator fixing an S3 configuration issue can launch a one-time session with AWS's AmazonS3FullAccess policy:31
CYNATIVE_CONNECTORS_AWS_POLICY=arn:aws:iam::aws:policy/AmazonS3FullAccess \ cynative -p "Enable versioning on the example-data bucket"
The override replaces the default action policy for this invocation, allowing S3 administration within the permissions of the AWS identity in use. The operator chooses this session-specific privilege increase at startup; the model cannot make that choice during an investigation. A later invocation without the override returns to the configured default.19
The same variable can select an existing customer-managed policy for a recurring incident-response workflow or organization-specific scope. With a customer-managed copy of SecurityAudit, the organization takes responsibility for keeping it up to date.1928
A dedicated least-privilege role is a good foundation where an organization can provide one. Creating it involves trust, permissions, and credential configuration, often with an approval process. The local gateway also works with the operator's existing credentials, so that setup can follow rather than block the first investigation.3219
For assumed-role identities, Cynative can also obtain an STS session restricted by the selected policy. This adds AWS-side enforcement alongside the gateway's pre-signing check.19
How this differs from AWS API MCP's read-only mode
The self-hosted AWS API MCP Server also offers broad AWS access through a compact interface. AWS has since superseded it with a managed server, but the managed server's read-only mode works at the tool level: it disables call_aws entirely rather than deciding which operations through it are safe. The self-hosted code remains the only AWS implementation that classifies individual operations, which is why it's the one we compare against. Its call_aws tool accepts CLI commands and relies on the installed CLI and SDK.3334
Both approaches avoid thousands of individual tools. The difference is how they expose native calls and decide which operations belong in an investigation.333
The server's optional read-only classifier checks explicit overrides, bundled ReadOnly metadata, and custom CLI additions. When these do not identify a read-only operation, it consults live Service Reference data for IAM action names whose IsWrite property is false.35
That live lookup compares the supplied operation name with non-write IAM action names. Cynative resolves an operation's required actions through Operations[].AuthorizedActions before applying an audit policy, allowing the API operation and IAM actions to have different names. The selected policy then determines scope, including the distinction between inspecting a secret's configuration and retrieving its value.352515
Both implementations can run under a restricted AWS identity. The self-hosted server also supports a separate command policy, while its read-only flag classifies operations without narrowing the credentials. Cynative combines SecurityAudit policy evaluation before signing with STS session scoping where available.3319
Keep the interface broad and the authority explicit
The GKE test made the requirement concrete: a security agent should not change a cluster's access configuration just to inspect it. Reporting the change after the namespace list was useful for transparency, but the permitted scope needed to be enforced before the change happened.
HTTP lets the agent work with native APIs through one stable tool. AWS's models, permission reference, and default audit policy let the gateway follow service changes as data, rather than a growing collection of wrappers. The client then checks each request against the operator's chosen scope before attaching credentials.3525204
That is the coupling we want: flexible research code on one side, explicit authorization on the other, and a shared implementation that changes when the underlying contracts change, not every time AWS adds an operation.
- Google Cloud: DNS-based and IP-based access to the GKE control plane.
- Cynative: project overview and sandbox design.
- Cynative: the generic
http_requesttool, shared request schema, and code-composition workflow. - Cynative: request authorization and authentication order.
- Cynative: runtime archive retrieval and model archive, version selection, and dynamic index.
- Cloudflare: Code Mode and its rationale.
- AWS: Overview of Amazon Web Services and AWS CLI and Agent Toolkit announcement.
- Cynative: Smithy parser, accepted version family, and supported protocol traits.
- Cynative: host parsing and endpoint conventions and host-claim verification, canonical signing names, payload hashing, and SigV4 injection.
- AWS News Blog, June 5, 2025: Introducing AWS API models and publicly available resources for AWS API definitions. AWS: API Models repository and directory structure.
- Botocore: serializer implementations in version 1.4.0, released March 2, 2016.
- AWS News Blog: Amazon S3 Update: SigV2 Deprecation Period Extended & Modified, which dates SigV4's introduction to 2012.
- Cynative: resolution tiers, naming fallback, namespace handling, and permissionless exception and candidate-model action union.
- AWS API references: DescribeSecret and GetSecretValue.
- AWS: SecurityAudit managed policy.
- Bonnie Brinton Anderson, Anthony Vance, C. Brock Kirwan, Jeffrey L. Jenkins, and David Eargle: From Warning to Wallpaper: Why the Brain Habituates to Security Warnings and What Can Be Done About It, Journal of Management Information Systems 33(3), 2016.
- Cynative: untrusted-output framing and delimiter escaping, system-prompt instructions, framing at the I/O dispatch boundary, and untrusted sub-agent summaries.
- Cynative:
--auto-approveflag and approval handling. - Cynative: AWS connector, policy selection, and session scoping.
- Cynative: live policy loading and action-level policy simulation and decision cache.
- Ian McKay: iamlive proxy mode.
- Cynative: JSON-RPC and Query operation classification.
- Cynative: REST matching, S3 virtual-host normalization, and discriminator scoring.
- AWS: ListObjectsV2 API permissions.
- AWS: Service Reference schema, operation mappings, coverage limitations, and publication delay. Cynative: Service Reference parser.
- Ian McKay: iam-dataset. Cynative: dataset integration.
- AWS STS: GetCallerIdentity.
- AWS IAM: job-function policies and managed-policy updates.
- Cynative: policy-denial error construction and direct and sandboxed tool error handling.
- Cynative: metadata cache lifecycle and archive caching.
- AWS: AmazonS3FullAccess managed policy.
- AWS IAM: Controlling access for AssumeRole and job-function policies.
- AWS Labs: self-hosted AWS API MCP Server documentation.
- AWS: migration to the managed AWS MCP Server, MCP Proxy's tool-level read-only option, and managed-server tools and call_aws deprecation.
- AWS Labs, commit
c9102a9a631fe0d8f4b1671b154ab2bb73484a5c: read-only classification and security-policy dispatch.