@highflame/policy 2.2.45 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4002,6 +4002,126 @@ unless {
4002
4002
  context has agent_trust_level && context.agent_trust_level == "first_party"
4003
4003
  };
4004
4004
  `;
4005
+ const GUARDRAILS_AGENT_IDENTITY_BLOCK_UNADOPTED_AGENT_SENSITIVE_TOOLS_CEDAR = `// =============================================================================
4006
+ // Unadopted Agents: No Sensitive Tool Calls
4007
+ // =============================================================================
4008
+ // Agents that an enterprise registers in its own IdP (Entra Agent ID, Okta AI
4009
+ // agents) are discovered by Highflame before anyone adopts them. A discovered
4010
+ // or pending agent has an identity but no owner-reviewed policy, so it should
4011
+ // not reach sensitive tools until it is adopted (status "active").
4012
+ //
4013
+ // \`context.actor.status\` carries the agent lifecycle status. When no actor
4014
+ // record is present the rule falls back to the legacy \`context.principal.status\`
4015
+ // profile. Absence means "unknown", not "active": the has-guards below make a
4016
+ // request with no status fall through to the other rules instead of being
4017
+ // matched here. Any status other than "active" is matched, so suspended and
4018
+ // deactivated agents are blocked too. The comparison is case-sensitive, like
4019
+ // ZeroID's lowercase status values.
4020
+ //
4021
+ // Today this template is forward-looking. ZeroID mints tokens only for active
4022
+ // identities and stamps "active" at mint, and every caller of Shield forwards
4023
+ // that value, so no live path reports another status yet. It takes effect when
4024
+ // a non-active status reaches Shield, as ADR 0042 plans for agents registered
4025
+ // in a customer IdP. The status is a mint-time snapshot: an identity suspended
4026
+ // after its token was minted reads "active" until the token expires.
4027
+ //
4028
+ // \`tool_is_sensitive\` is set by Shield's tool_validator from a fixed list of
4029
+ // tool names (shell, execute_command, write_file, http_post, send_email,
4030
+ // delete_file, run_sql, plus Shield's configured list); other tools are not
4031
+ // sensitive and are not matched.
4032
+ //
4033
+ // This copy covers Guardrails traffic. Gateway traffic (Firehog) is evaluated
4034
+ // in the AIGateway namespace; use the AIGateway copy for it.
4035
+ //
4036
+ // Deploy in MONITOR mode first to see which discovered agents already call
4037
+ // sensitive tools, adopt them, then switch to enforce.
4038
+ //
4039
+ // Context keys consumed:
4040
+ // - actor, principal: records - status is the agent lifecycle status
4041
+ // - tool_is_sensitive: Bool
4042
+ //
4043
+ // Compliance:
4044
+ // - OWASP ASI04
4045
+ //
4046
+ // Category: agent-identity
4047
+ // Namespace: Guardrails
4048
+ // =============================================================================
4049
+
4050
+ @id("agent-identity.block-unadopted-agent-sensitive-tools")
4051
+ @name("Block unadopted agents from sensitive tools")
4052
+ @description("Blocks call_tool on a sensitive tool when actor.status (or, without an actor record, principal.status) is present and is not active.")
4053
+ @severity("high")
4054
+ @tags("category:agent-identity,detection:rule,surface:call-tool,scope:per-agent,posture:deny-default,owasp:asi04")
4055
+ @reject_message("Tool execution blocked: this agent has not been adopted, so it may not call sensitive tools. Adopt the agent to activate it.")
4056
+ forbid (
4057
+ principal,
4058
+ action == Guardrails::Action::"call_tool",
4059
+ resource
4060
+ )
4061
+ when {
4062
+ (
4063
+ (context has actor && context.actor has status && context.actor.status != "active") ||
4064
+ (!(context has actor) && context has principal && context.principal has status &&
4065
+ context.principal.status != "active")
4066
+ ) &&
4067
+ context has tool_is_sensitive && context.tool_is_sensitive
4068
+ };
4069
+ `;
4070
+ const GUARDRAILS_AGENT_IDENTITY_PERMIT_SINGLE_USE_SENSITIVE_TOOLS_CEDAR = `// =============================================================================
4071
+ // Single-Use for Sensitive Tools
4072
+ // =============================================================================
4073
+ // Permits sensitive tool calls, but only once per grant. @single_use makes
4074
+ // Shield record the first allow in an atomic consume store and deny any replay
4075
+ // of the same grant ("grant_consumed"). Bare @single_use means per tool: one
4076
+ // allow covers any call to the same action and tool. Use
4077
+ // @single_use("request") instead to bind the allow to one exact set of
4078
+ // arguments.
4079
+ //
4080
+ // @single_use is only valid on a permit. Deny, DEFER and step-up outcomes
4081
+ // never consume. If the consume store is unavailable the request is denied
4082
+ // ("single_use_store_unavailable") unless the operator opted into fail-open.
4083
+ //
4084
+ // Requests that carry no bearer token, such as gateway and internal-service
4085
+ // traffic, have no token id to record the use against. Shield denies every
4086
+ // sensitive call_tool from them ("single_use_unbound"), whatever the
4087
+ // fail-open setting. Until the gateway forwards the caller's token to Shield
4088
+ // (ADR 0041 D16, ADR 0042 D10), that means every sensitive gateway call.
4089
+ //
4090
+ // Try it with request-level monitor mode (guard requests sent with
4091
+ // mode=monitor): single_use.would_deny on each response shows what enforcing
4092
+ // would deny. Per-policy monitor mode does NOT exercise @single_use, because
4093
+ // Shield reads it only from enforcing policies; a monitor-mode copy of this
4094
+ // template reports nothing, and switching it to enforce takes effect at once.
4095
+ //
4096
+ // Adopted alone, this permit also allows every sensitive call_tool (once per
4097
+ // grant). Pair it with the policies that decide which sensitive calls are
4098
+ // allowed at all.
4099
+ //
4100
+ // Context keys consumed:
4101
+ // - tool_is_sensitive: Bool
4102
+ //
4103
+ // Compliance:
4104
+ // - OWASP ASI02
4105
+ //
4106
+ // Category: agent-identity
4107
+ // Namespace: Guardrails
4108
+ // =============================================================================
4109
+
4110
+ @id("agent-identity.permit-single-use-sensitive-tools")
4111
+ @name("Permit sensitive tools once per grant")
4112
+ @description("Permits call_tool on a sensitive tool once per grant.")
4113
+ @severity("medium")
4114
+ @tags("category:agent-identity,surface:call-tool,scope:per-tool,owasp:asi02,single-use")
4115
+ @single_use
4116
+ permit (
4117
+ principal,
4118
+ action == Guardrails::Action::"call_tool",
4119
+ resource
4120
+ )
4121
+ when {
4122
+ context has tool_is_sensitive && context.tool_is_sensitive
4123
+ };
4124
+ `;
4005
4125
  // =============================================================================
4006
4126
  // CATEGORIES
4007
4127
  // =============================================================================
@@ -4404,6 +4524,24 @@ export const GUARDRAILS_TEMPLATES = [
4404
4524
  severity: 'critical',
4405
4525
  tags: ['category:agent-identity', 'detection:rule', 'surface:call-tool', 'scope:per-agent', 'posture:deny-default', 'owasp:asi01'],
4406
4526
  },
4527
+ {
4528
+ id: 'agent-identity.block-unadopted-agent-sensitive-tools',
4529
+ name: 'Unadopted Agents: No Sensitive Tool Calls',
4530
+ description: 'Block sensitive tool calls from agents whose lifecycle status is not active (discovered or pending). Deploy in monitor mode first to see which discovered agents already call sensitive tools.',
4531
+ category: 'agent-identity',
4532
+ cedarText: GUARDRAILS_AGENT_IDENTITY_BLOCK_UNADOPTED_AGENT_SENSITIVE_TOOLS_CEDAR,
4533
+ severity: 'high',
4534
+ tags: ['category:agent-identity', 'detection:rule', 'surface:call-tool', 'scope:per-agent', 'posture:deny-default', 'owasp:asi04'],
4535
+ },
4536
+ {
4537
+ id: 'agent-identity.permit-single-use-sensitive-tools',
4538
+ name: 'Single-Use for Sensitive Tools',
4539
+ description: 'Permit sensitive tool calls once per grant: the first allow is recorded and a replay of the same grant is denied. Bare @single_use means per tool; use @single_use(\"request\") to bind to one set of arguments. Requests without a bearer token (gateway and internal-service traffic, until the gateway forwards the caller token) are denied (single_use_unbound). Try it with request-level mode=monitor: per-policy monitor mode does not exercise @single_use. Adopted alone, it also permits every sensitive call.',
4540
+ category: 'agent-identity',
4541
+ cedarText: GUARDRAILS_AGENT_IDENTITY_PERMIT_SINGLE_USE_SENSITIVE_TOOLS_CEDAR,
4542
+ severity: 'medium',
4543
+ tags: ['category:agent-identity', 'surface:call-tool', 'scope:per-tool', 'owasp:asi02', 'single-use'],
4544
+ },
4407
4545
  ];
4408
4546
  // =============================================================================
4409
4547
  // TEMPLATES METADATA
@@ -5060,6 +5198,37 @@ export const GUARDRAILS_TEMPLATES_JSON = `{
5060
5198
  "posture:deny-default",
5061
5199
  "owasp:asi01"
5062
5200
  ]
5201
+ },
5202
+ {
5203
+ "id": "agent-identity.block-unadopted-agent-sensitive-tools",
5204
+ "name": "Unadopted Agents: No Sensitive Tool Calls",
5205
+ "description": "Block sensitive tool calls from agents whose lifecycle status is not active (discovered or pending). Deploy in monitor mode first to see which discovered agents already call sensitive tools.",
5206
+ "category": "agent-identity",
5207
+ "file": "unadopted_agents.cedar",
5208
+ "severity": "high",
5209
+ "tags": [
5210
+ "category:agent-identity",
5211
+ "detection:rule",
5212
+ "surface:call-tool",
5213
+ "scope:per-agent",
5214
+ "posture:deny-default",
5215
+ "owasp:asi04"
5216
+ ]
5217
+ },
5218
+ {
5219
+ "id": "agent-identity.permit-single-use-sensitive-tools",
5220
+ "name": "Single-Use for Sensitive Tools",
5221
+ "description": "Permit sensitive tool calls once per grant: the first allow is recorded and a replay of the same grant is denied. Bare @single_use means per tool; use @single_use(\\"request\\") to bind to one set of arguments. Requests without a bearer token (gateway and internal-service traffic, until the gateway forwards the caller token) are denied (single_use_unbound). Try it with request-level mode=monitor: per-policy monitor mode does not exercise @single_use. Adopted alone, it also permits every sensitive call.",
5222
+ "category": "agent-identity",
5223
+ "file": "single_use_sensitive_tools.cedar",
5224
+ "severity": "medium",
5225
+ "tags": [
5226
+ "category:agent-identity",
5227
+ "surface:call-tool",
5228
+ "scope:per-tool",
5229
+ "owasp:asi02",
5230
+ "single-use"
5231
+ ]
5063
5232
  }
5064
5233
  ]
5065
5234
  }