An Amazon Bedrock agent turns natural language into API calls, so every action group it can reach is a permission that a prompt, a document or a tool response can try to use. The agent runs under a service role, calls tools through Lambda functions or hands control back to your application, keeps session attributes and optional cross-session memory, and applies a guardrail only if you attach one. This guide goes deep on hardening those parts for teams that already run Bedrock Agents: action group design, the service role and Lambda resource policies, user confirmation, session and memory isolation, guardrails, encryption, logging and rollout. It is for cloud security engineers, AI platform owners and developers who build agent tools. Account-wide Bedrock controls such as model access, API keys and invocation logging are in the Amazon Bedrock Security Guide, and finding the agents you already have is covered in How to inventory AI agents in AWS Bedrock.
This is an independent guide from NHI Mgmt Group, based on AWS's public documentation as of November 2026. It is not sponsored or reviewed by AWS. Product features change, so confirm settings against AWS's current documentation.
Key takeaways
- The action group is the real permission boundary. Whatever the Lambda function's execution role or your return-control handler can do, the agent can be talked into attempting, so design tools narrowly and authorise every call in code.
- Pin the service role and every Lambda policy to specific agents. Use aws:SourceAccount and AWS:SourceArn with real agent IDs, not agent/*, on the role trust policy and on each action group function.
- Require confirmation for state-changing actions. Set requireConfirmation to ENABLED so the user must CONFIRM before the function runs; AWS documents this as a safeguard against prompt injection carried in tool and knowledge base responses.
- Identity comes from your application, never from the model. Pass the authenticated user in sessionAttributes, bind sessionId and memoryId to that user, and make tools decide access from it.
- Guardrails, pre-processing and logs are things you switch on. Attach a guardrail with guardrailConfiguration, enable the pre-processing prompt, encrypt with a customer managed key and turn on CloudTrail data events for InvokeAgent.
Service status and scope
As of November 2026 the AWS documentation states that sign-up for Amazon Bedrock Agents, now called Amazon Bedrock Agents Classic, has closed, that existing customers can continue to use it, and that AWS points new builds to Amazon Bedrock AgentCore for similar capabilities. This guide is therefore for organisations that run Agents Classic today and need to harden what is in production. If you are starting a new agent, read the AWS Bedrock AgentCore Security Guide instead: AgentCore is a different service with its own identity, gateway and policy model.
How a Bedrock agent acts, and where the trust boundaries sit
An agent is defined by a foundation model, an instruction, optional action groups, optional knowledge bases, an optional guardrail and a service role. You deploy it by creating a version and an alias that points to that version; the console and API use the alias ID TSTALIASID for the working draft. During orchestration the model chooses an action, Bedrock fills in parameters, and the action is fulfilled in one of four ways: by asking the user for more input, by calling a Lambda function, by returning control to your application, or by asking the user to confirm first.
| Component | What it can do | Trust boundary to defend |
|---|---|---|
| Agent service role (agentResourceRoleArn) | Invoke the orchestration model, read the OpenAPI schema from S3, call Retrieve on knowledge bases, apply the guardrail, invoke collaborator aliases | Who can assume it (trust policy) and which ARNs it reaches |
| Action group Lambda function | Runs your business logic with its own execution role | Resource-based policy (who may invoke) and execution role (what it may change) |
| Return control handler | Your application receives the elicited parameters and runs the action itself | Your code: allow-list, validation, authorisation |
| Session state | sessionAttributes last for the session; promptSessionAttributes last one turn and can be inserted into the orchestration prompt | Who sets them: only your application or your Lambda |
| Memory | Session summaries kept across sessions against a memoryId, for 1 to 365 days | One memoryId per user, retention, deletion |
| Knowledge bases | Retrieved text enters the model context | Data classification per knowledge base; injected instructions in documents |
| Collaborator agents | A supervisor (agentCollaboration SUPERVISOR or SUPERVISOR_ROUTER) invokes other agent aliases | bedrock:InvokeAgent scoped to named collaborator aliases; conversation history sharing |
The model is not a security control. It selects actions and fills parameters from text that may include user input, retrieved documents and earlier tool responses. Authorisation, validation and approval must sit in components that the model cannot rewrite. See the Confused Deputy in AI Agents Guide for the general pattern.
Designing action groups with least privilege
An action group is defined either with an OpenAPI schema (stored in S3 or inline) or with function details, and one Lambda function serves every operation in the group, routing on apiPath and httpMethod or on function. That shared function is where over-privilege accumulates, because a read operation and a write operation end up under one execution role.
- Split read and write: put lookups and changes in separate action groups with separate Lambda functions and execution roles, so a prompt that reaches a read tool cannot borrow write permissions.
- Narrow operations, not generic ones: expose cancelBooking(bookingId) rather than a generic database or HTTP proxy. A tool that accepts a free-form query or URL hands the model the full power of the execution role.
- Protect the schema object: the service role reads the OpenAPI schema with s3:GetObject. Anyone who can write that object can add operations, so restrict s3:PutObject on the schema prefix to the deployment pipeline and turn on S3 versioning.
- Use REPROMPT and FAILURE deliberately: in a function details response, responseState REPROMPT sends the message back to the model for invalid input, and FAILURE raises a DependencyFailedException for the session. Use REPROMPT for bad parameters and FAILURE for authorisation denials.
- Keep responses minimal: the responseBody goes back into the model context. Return only what the user is entitled to see, never secrets, tokens or other users' records.
Lambda versus return control
| Option | Set by | Choose it when | Security trade-off |
|---|---|---|---|
| Lambda function | actionGroupExecutor with a Lambda ARN | The action is self-contained and can run with a dedicated, scoped execution role | The function role is a standing non-human identity; it needs its own least-privilege review and a resource policy pinned to the agent |
| Return control | actionGroupExecutor with customControl RETURN_CONTROL | The action must run with the end user's own credentials or inside an application that already enforces authorisation | No extra AWS role, but your code must validate invocationId, function name and parameters before acting |
| User confirmation | requireConfirmation ENABLED on the function or API | The action changes state, spends money, sends messages or deletes data | Adds a step for the user; the approval screen must show the real parameters, not the model's summary |
Return control is often the stronger pattern for actions on behalf of a user, because the call runs under the application's existing session and permission model rather than a shared Lambda role. When you use it, treat the returned invocationInputs as untrusted: dispatch only to an allow-listed set of functions, check that the invocationId is one you issued and has not been used, validate every parameter, and then enforce the user's permissions before calling the backend. Results go back in sessionState.returnControlInvocationResults on the next InvokeAgent call. See the Tool-Call Security for AI Agents guide.
The agent service role and Lambda resource policies
AWS documents a trust policy that lets bedrock.amazonaws.com call sts:AssumeRole with two conditions: aws:SourceAccount equal to your account ID and AWS:SourceArn matching arn:aws:bedrock:region:account-id:agent/*. AWS advises replacing the wildcard with specific agent IDs once the agents exist. Do that in every production account: the condition is the confused-deputy protection, and a wildcard lets any agent in the account assume a role built for another.
| Statement | Actions | Scope it to |
|---|---|---|
| Model invocation | bedrock:InvokeModel; with an inference profile also bedrock:InvokeModelWithResponseStream, bedrock:GetInferenceProfile, bedrock:GetFoundationModel | The single orchestration model ARN and named inference profile |
| Action group schema | s3:GetObject | The exact schema object, with aws:ResourceAccount set to your account |
| Knowledge base query | bedrock:Retrieve, bedrock:RetrieveAndGenerate | Named knowledge base ARNs only |
| Guardrail | bedrock:ApplyGuardrail (plus KMS decrypt if the guardrail uses a customer managed key) | The attached guardrail ARN |
| Multi-agent collaboration | bedrock:GetAgentAlias, bedrock:InvokeAgent | Named agent-alias ARNs of collaborators |
| Code interpretation with S3 files | s3:GetObject, s3:GetObjectVersion, s3:GetObjectAttributes, s3:GetObjectVersionAttributes | The specific bucket and key the agent needs |
| Third-party vector store | bedrock:AssociateThirdPartyKnowledgeBase | The knowledge base, with bedrock:ThirdPartyKnowledgeBaseCredentialsSecretArn set |
Omit every statement the agent does not use. Each action group Lambda function also needs a resource-based policy allowing lambda:InvokeFunction from bedrock.amazonaws.com, conditioned on AWS:SourceAccount and on AWS:SourceArn equal to the specific agent ARN. Two further controls belong around the role:
- iam:PassRole: builders who create or update agents need iam:PassRole for the service role. Scope it to named agent roles with the iam:PassedToService condition set to bedrock.amazonaws.com, so nobody can attach a broader role. See the AWS IAM Policies and Roles Guide.
- Permissions boundaries for builder-created roles: where developers may create their own agent and Lambda roles, require a permissions boundary on those roles. See the AWS IAM Permissions Boundaries Guide.
Prompt injection and approval controls
AWS's user confirmation documentation is direct about the threat: agents follow instructions found in API and knowledge base responses, and those responses can carry prompt injections that try to trigger unintended actions. Its prompt injection guidance places prevention under the customer side of the shared responsibility model and lists three agent measures: associate a guardrail, enable the default pre-processing prompt through advanced prompts, and use the system prompt to define clearly what the agent can and cannot do. Layer them with confirmation and code-level authorisation.
| Control | Setting | What it stops | What it does not stop |
|---|---|---|---|
| User confirmation | requireConfirmation ENABLED; user returns confirmationState CONFIRM or DENY | Silent execution of injected state-changing actions | A user who approves without reading; read-only data leakage |
| Guardrail | guardrailConfiguration with guardrailIdentifier and guardrailVersion on CreateAgent or UpdateAgent | Known prompt attack patterns, denied topics, sensitive information in user messages and model responses | Novel injections; authorisation decisions |
| Pre-processing prompt | Advanced prompts, pre-processing step enabled, optionally with a custom parser Lambda | Inputs classified as unsafe before orchestration | Instructions that arrive later in tool or retrieval output |
| Scoped instruction | Agent instruction and orchestration prompt | Off-topic use | Determined injection; never rely on it alone |
| Authorisation in tools | Lambda or return-control code checks the user from sessionAttributes | Actions on records the user may not touch, whatever the model asked for | Actions the user is genuinely allowed to take |
Use a published guardrail version in production rather than the working draft, so a change to the guardrail goes through the same release step as the agent. The threat maps to OWASP LLM01:2025 Prompt Injection and LLM06:2025 Excessive Agency, MITRE ATT&CK T1698 Indirect Prompt Injection and T1699 Direct Prompt Injection, and MITRE ATLAS AML.T0051 LLM Prompt Injection and AML.T0053 AI Agent Tool Invocation. See the OWASP LLM Top 10 LLM06 Excessive Agency Guide and the Human-in-the-Loop for AI Agents Guide.
Sessions, attributes and memory isolation
Bedrock Agents has no built-in notion of the end user. Your application decides who the user is and must carry that identity in a form the model cannot alter.
- sessionAttributes for identity: session attributes persist for the session and are sent to the action group Lambda in the input event. Set the authenticated user ID, tenant and roles here from your own session, and have every tool read identity from sessionAttributes, never from parameters the model filled in.
- promptSessionAttributes with care: these last one turn and appear in the orchestration prompt when the template includes the $prompt_session_attributes$ placeholder. Put only context the model needs (time zone, locale), never secrets or entitlements.
- sessionId binding: all InvokeAgent calls with the same sessionId share one session until idleSessionTTLInSeconds (60 to 5,400 seconds) passes. Generate session IDs server-side, store them against the authenticated user, and reject a sessionId presented by a different user. Set the TTL to the shortest value the use case tolerates.
- memoryId per user: when memory is enabled, sessions are summarised into memory when endSession is true or the idle timeout elapses. AWS tells you to use the same memoryId for the same user; the corollary is that a shared or guessable memoryId loads one user's summaries into another user's session. Derive it from the internal user ID, not from anything the user types.
- Retention and deletion: memory keeps summaries for up to 365 days and you can set storageDays between 1 and 365. Set the shortest period that serves the use case, and wire data subject deletion requests to DeleteAgentMemory for that memoryId. Summaries are personal data where the conversations are. See the AI Agent Memory Security Guide.
Encryption of agent resources
Bedrock encrypts agent session information by default with an AWS managed key, and you can supply a customer managed key with customerEncryptionKeyArn. The AWS key policy pattern scopes Bedrock's kms:GenerateDataKey and kms:Decrypt to one agent with the condition kms:EncryptionContext:aws:bedrock:arn equal to the agent ARN, and allows kms:CreateGrant only when kms:GrantIsForAWSResource is true. The caller of InvokeAgent also needs kms:GenerateDataKey and kms:Decrypt under the same encryption context condition. AWS documents different key policy instructions for agents created before 22 January 2025 and after, so check the creation date of each agent before you change its key. See the AWS KMS Security Guide.
Multi-agent collaboration
A supervisor agent invokes collaborators through their aliases, so the attack surface is the union of all collaborators' roles and tools.
- Scope InvokeAgent: the supervisor's service role should list each collaborator alias ARN, not agent-alias/*.
- Limit history sharing: when conversation history sharing is enabled for a collaborator, the supervisor passes the conversation to it. Turn it off for collaborators that do not need the full context, especially where the conversation holds personal data.
- Route return control correctly: in multi-agent return control the results must carry the collaborator agentId so they reach the right agent; validate it like any other returned field.
Detection and measurement
Agent runtime calls are data events in CloudTrail, which are off by default; control plane changes are management events. Model invocation logging adds the prompts and responses, as described in the Amazon Bedrock Security Guide.
| Signal | Source | Why it matters |
|---|---|---|
| InvokeAgent by principal, alias and source | CloudTrail data events on AWS::Bedrock::AgentAlias | New callers, direct calls to TSTALIASID in production, unusual volume |
| UpdateAgent, CreateAgentActionGroup, UpdateAgentActionGroup, PrepareAgent, alias updates | CloudTrail management events | Tool, instruction or role changes outside the pipeline role |
| Changes to guardrailConfiguration or guardrail versions | CloudTrail management events | Weakening of the safety layer |
| PutObject on action group schema objects | S3 data events | Tools added without a code change |
| Confirmation DENY rate, REPROMPT and FAILURE responses from tools | Application and Lambda logs | Probing and injected actions being blocked |
| Guardrail interventions per agent | Guardrail metrics and trace | Prompt attack attempts |
Metrics that show the controls are working:
- Percentage of agent service roles and action group Lambda policies with AWS:SourceArn pinned to a specific agent ID (target 100).
- Percentage of state-changing functions with requireConfirmation ENABLED or fulfilled through return control with server-side authorisation (target 100).
- Percentage of production agents with a published guardrail version attached.
- Number of action group execution roles with wildcard actions or resources (target 0).
- Agent changes made outside the deployment pipeline per month (target 0).
- Memory retention days per agent against the approved maximum.
Rollout plan
- Inventory: list agents, aliases, action groups, Lambda functions, knowledge bases and service roles in every account and Region.
- Pin trust first: replace agent/* in service role trust policies and Lambda resource policies with specific agent ARNs. Test with PrepareAgent and a TSTALIASID session before updating production aliases.
- Turn on visibility: enable CloudTrail data events for agent aliases and S3 data events on schema buckets, then baseline normal callers for two weeks.
- Add approvals: enable requireConfirmation on state-changing functions in a new agent version, test in a pilot alias with a small user group, then move the production alias. Rollback is pointing the alias back to the previous version.
- Move identity into sessionAttributes: change tools to read the user from session attributes and enforce access in code; bind sessionId and memoryId to the authenticated user.
- Attach guardrails and pre-processing: publish a guardrail version, attach it and enable the pre-processing step; review false positives in the pilot alias first.
- Split and shrink roles: separate read and write action groups, remove unused statements from service roles and run IAM Access Analyzer unused access findings on execution roles. See the IAM Access Analyzer Guide.
- Decide the future: because Agents Classic is closed to new sign-ups, record for each agent whether to keep, retire or rebuild on AgentCore, and retire unused agents and aliases now.
Small versus large estates: a team with one or two agents gets most of the benefit from steps 2, 4 and 5. Large organisations should also put agent changes behind a pipeline role, deny UpdateAgent and action group changes to humans in production accounts with an SCP (see the AWS Organizations and SCPs Guide), and review every agent as a non-human identity on a recertification cycle.
Common failure patterns
- One Lambda for everything: read and write operations share a function whose execution role can modify production data, so a single injected instruction reaches write access.
- Wildcard source ARNs left in place: the documented agent/* example is copied into production and never narrowed, letting any agent in the account use the role or invoke the function.
- User identity taken from model parameters: a tool accepts customerId as a parameter and trusts it, so a user can ask the agent to act on someone else's record.
- Shared memoryId or client-supplied sessionId: summaries or live session context leak between users.
- Trace exposed to end users: enableTrace output, which includes reasoning, parameters and tool outputs, is passed to the client. Keep trace off in user-facing paths or restrict who reads it.
Framework mapping
| Control area | NIST SP 800-53 Rev 5 | NIST CSF 2.0 | ISO/IEC 27001:2022 Annex A | CIS Controls v8.1 |
|---|---|---|---|---|
| Scoped service and execution roles | AC-6, AC-6(1) | PR.AA-05 | A.5.15, A.8.2 | 6 Access Control Management |
| Authorisation in tools | AC-3 | PR.AA-05 | A.5.15, A.8.26 | 6 |
| Parameter validation | SI-10 | PR.PS-06 | A.8.28 | 16 Application Software Security |
| Change control for agents and tools | CM-5 | PR.PS-01 | A.8.32 | 4 Secure Configuration |
| Logging and monitoring | AU-2, AU-12 | PR.PS-04, DE.CM-09 | A.8.15, A.8.16 | 8 Audit Log Management |
Practitioner checklist
- Inventory every Agents Classic agent, alias, action group and role, and record a keep, retire or rebuild decision.
- Replace agent/* with specific agent ARNs in service role trust policies and Lambda resource policies.
- Remove unused statements from service roles and scope each to named models, knowledge bases, guardrails and aliases.
- Split read and write tools into separate action groups and execution roles.
- Set requireConfirmation to ENABLED on every state-changing function, or use return control with server-side authorisation.
- Carry user identity in sessionAttributes and enforce access in tool code; bind sessionId and memoryId to the authenticated user.
- Attach a published guardrail version and enable the pre-processing prompt.
- Use a customer managed KMS key scoped with kms:EncryptionContext:aws:bedrock:arn.
- Enable CloudTrail data events for agent aliases and alert on agent, action group and schema changes outside the pipeline.
- Set memory storageDays to the approved minimum and connect deletion requests to DeleteAgentMemory.
Standards and references
- AWS: Create a service role for Amazon Bedrock Agents
- AWS: Get user confirmation before invoking action group function
- AWS: Return control to the agent developer
- AWS: Configure Lambda functions to send information that a Bedrock agent elicits
- AWS: Control agent session context
- AWS: Retain conversational context across multiple sessions using memory
- AWS: Prompt injection security
- OWASP: LLM06:2025 Excessive Agency
Related NHI Mgmt Group resources: Amazon Bedrock Security Guide · AWS Bedrock AgentCore Security Guide · Agentic AI Security Guide · Agentic AI Identity Guide · Prompt Injection Guide