Documentation
¶
Overview ¶
Package action defines the CanonicalAction type system: a protocol-agnostic representation of any agent action flowing through SentinelGate. Every action — regardless of protocol (MCP, HTTP, WebSocket, runtime) — is normalized into a CanonicalAction for uniform policy evaluation.
Index ¶
- Constants
- Variables
- func MatchRule(rule OutboundRule, domain string, ip string, port int) bool
- func MatchTarget(target OutboundTarget, domain string, ip string, port int) bool
- type ActionIdentity
- type ActionInterceptor
- type ActionInterceptorFunc
- type ActionType
- type ApprovalInterceptor
- type ApprovalResult
- type ApprovalStore
- type CanonicalAction
- type DNSResolver
- type DNSResolverOption
- type Decision
- type Destination
- type ExtractOptions
- type ExtractedURL
- type HTTPNormalizer
- type InterceptResult
- type InterceptorChain
- type LegacyAdapter
- type MCPNormalizer
- type MemoryOutboundStore
- func (s *MemoryOutboundStore) Delete(_ context.Context, id string) error
- func (s *MemoryOutboundStore) Get(_ context.Context, id string) (*OutboundRule, error)
- func (s *MemoryOutboundStore) List(_ context.Context) ([]OutboundRule, error)
- func (s *MemoryOutboundStore) Save(_ context.Context, rule *OutboundRule) error
- type Normalizer
- type OutboundDenyError
- type OutboundInterceptor
- type OutboundRule
- type OutboundRuleStore
- type OutboundTarget
- type PendingApproval
- type PolicyActionInterceptor
- type QuarantineChecker
- type QuarantineInterceptor
- type ResolvedDest
- type ResponseScanInterceptor
- func (r *ResponseScanInterceptor) Enabled() bool
- func (r *ResponseScanInterceptor) Intercept(ctx context.Context, a *CanonicalAction) (*CanonicalAction, error)
- func (r *ResponseScanInterceptor) Mode() ScanMode
- func (r *ResponseScanInterceptor) SetEnabled(enabled bool)
- func (r *ResponseScanInterceptor) SetMode(mode ScanMode)
- type ResponseScanner
- type RuleAction
- type RuleMode
- type ScanFinding
- type ScanMode
- type ScanResult
- type TargetType
Constants ¶
const ( // DefaultApprovalTimeout is the default timeout for pending approvals. DefaultApprovalTimeout = 5 * time.Minute // DefaultMaxPending is the default maximum number of pending approvals. DefaultMaxPending = 100 )
Variables ¶
var ErrOutboundBlocked = fmt.Errorf("outbound blocked")
ErrOutboundBlocked is the sentinel error for outbound-blocked actions.
var ErrOutboundRuleNotFound = errors.New("outbound rule not found")
ErrOutboundRuleNotFound is returned when a requested outbound rule does not exist.
var ErrResponseBlocked = errors.New("response blocked by content scanning")
ErrResponseBlocked is returned when response content scanning detects prompt injection in enforce mode.
Functions ¶
func MatchRule ¶
func MatchRule(rule OutboundRule, domain string, ip string, port int) bool
MatchRule returns true if ANY target in the rule matches the given destination.
func MatchTarget ¶
func MatchTarget(target OutboundTarget, domain string, ip string, port int) bool
MatchTarget evaluates whether a single target matches the given destination properties (domain, ip, port).
Types ¶
type ActionIdentity ¶
type ActionIdentity struct {
// ID is the unique identifier for the actor.
ID string
// Name is the display name of the actor.
Name string
// Roles are the roles assigned to the actor.
Roles []string
// SessionID is the session identifier for the actor.
SessionID string
}
ActionIdentity represents the WHO of an action: the actor performing it.
type ActionInterceptor ¶
type ActionInterceptor interface {
// Intercept processes a CanonicalAction and returns the result.
// Returns the (possibly modified) action and an error if rejected.
Intercept(ctx context.Context, action *CanonicalAction) (*CanonicalAction, error)
}
ActionInterceptor processes CanonicalActions through the security chain. This is the protocol-agnostic replacement for proxy.MessageInterceptor. During migration, LegacyAdapter wraps existing MessageInterceptors.
type ActionInterceptorFunc ¶
type ActionInterceptorFunc func(ctx context.Context, action *CanonicalAction) (*CanonicalAction, error)
ActionInterceptorFunc is an adapter to allow the use of ordinary functions as ActionInterceptors. Like http.HandlerFunc, it enables inline interceptors.
func (ActionInterceptorFunc) Intercept ¶
func (f ActionInterceptorFunc) Intercept(ctx context.Context, action *CanonicalAction) (*CanonicalAction, error)
Intercept calls f(ctx, action).
type ActionType ¶
type ActionType string
ActionType categorizes the kind of action being performed.
const ( // ActionToolCall represents an MCP tools/call or equivalent tool invocation. ActionToolCall ActionType = "tool_call" // ActionHTTPRequest represents an outbound HTTP request from an agent. ActionHTTPRequest ActionType = "http_request" // ActionWebSocketMessage represents a WebSocket message. ActionWebSocketMessage ActionType = "websocket_message" // ActionCommandExec represents a command execution (shell, subprocess). ActionCommandExec ActionType = "command_exec" // ActionFileAccess represents a file read/write/delete operation. ActionFileAccess ActionType = "file_access" // ActionNetworkConnect represents a raw network connection attempt. ActionNetworkConnect ActionType = "network_connect" // ActionSampling represents an MCP sampling/createMessage request. ActionSampling ActionType = "sampling" // ActionElicitation represents an MCP elicitation/create request. ActionElicitation ActionType = "elicitation" )
func (ActionType) String ¶
func (t ActionType) String() string
String returns the string representation of the ActionType.
type ApprovalInterceptor ¶
type ApprovalInterceptor struct {
// contains filtered or unexported fields
}
ApprovalInterceptor blocks tool calls that require human approval. It reads the policy Decision from context (set by PolicyActionInterceptor). If RequiresApproval is true, it creates a PendingApproval entry and blocks until the request is approved, denied, or times out.
func NewApprovalInterceptor ¶
func NewApprovalInterceptor(store *ApprovalStore, next ActionInterceptor, logger *slog.Logger) *ApprovalInterceptor
NewApprovalInterceptor creates a new ApprovalInterceptor.
func (*ApprovalInterceptor) Intercept ¶
func (a *ApprovalInterceptor) Intercept(ctx context.Context, act *CanonicalAction) (*CanonicalAction, error)
Intercept checks if the tool call requires approval. If so, it blocks until the request is approved, denied, or times out. Otherwise, it passes through.
type ApprovalResult ¶
ApprovalResult carries the outcome of an approval decision.
type ApprovalStore ¶
type ApprovalStore struct {
// contains filtered or unexported fields
}
ApprovalStore manages pending approval requests with bounded capacity. It is thread-safe and supports FIFO eviction when capacity is reached.
func NewApprovalStore ¶
func NewApprovalStore(maxSize int) *ApprovalStore
NewApprovalStore creates a new ApprovalStore with the given maximum capacity.
func (*ApprovalStore) Add ¶
func (s *ApprovalStore) Add(approval *PendingApproval) string
Add stores a new pending approval and returns its ID. If the store is at capacity, the oldest pending approval is evicted (auto-denied).
func (*ApprovalStore) Approve ¶
func (s *ApprovalStore) Approve(id string) error
Approve sends an approval result to the blocked goroutine and removes the entry.
func (*ApprovalStore) Deny ¶
func (s *ApprovalStore) Deny(id, reason string) error
Deny sends a denial result to the blocked goroutine and removes the entry.
func (*ApprovalStore) Get ¶
func (s *ApprovalStore) Get(id string) *PendingApproval
Get returns a pending approval by ID, or nil if not found.
func (*ApprovalStore) List ¶
func (s *ApprovalStore) List() []*PendingApproval
List returns all pending approvals (status == "pending").
type CanonicalAction ¶
type CanonicalAction struct {
// Identity identifies the actor performing the action.
Identity ActionIdentity
// Type categorizes the action (tool_call, http_request, etc.).
Type ActionType
// Name is the action name (tool name, HTTP method, command name, etc.).
Name string
// Arguments contains the action parameters (tool args, query params, etc.).
Arguments map[string]interface{}
// Destination captures the target of the action.
Destination Destination
// Protocol is the originating protocol (mcp, http, websocket, runtime).
Protocol string
// Framework is the agent framework (crewai, autogen, langchain, etc.).
Framework string
// Gateway is the gateway that received the action (mcp-gateway, http-gateway, runtime).
Gateway string
// RequestTime is when the action was received.
RequestTime time.Time
// RequestID uniquely identifies this action request.
RequestID string
// Metadata is an extensible bag for protocol-specific data.
Metadata map[string]interface{}
// OriginalMessage stores the original protocol-specific message
// (e.g., *mcp.Message, *http.Request) for denormalization.
OriginalMessage interface{}
}
CanonicalAction is the universal representation of any agent action. It uses a WHO/WHAT/WHERE/HOW/CONTEXT model to capture all relevant information for policy evaluation, regardless of the originating protocol.
type DNSResolver ¶
type DNSResolver struct {
// contains filtered or unexported fields
}
DNSResolver provides DNS resolution with per-request pinning and TTL-based caching. It prevents DNS rebinding attacks by pinning the first resolution result for the lifetime of a request.
func NewDNSResolver ¶
func NewDNSResolver(logger *slog.Logger, opts ...DNSResolverOption) *DNSResolver
NewDNSResolver creates a new DNS resolver with optional configuration.
func (*DNSResolver) CleanExpired ¶
func (r *DNSResolver) CleanExpired()
CleanExpired removes expired cache entries.
func (*DNSResolver) PinForRequest ¶
func (r *DNSResolver) PinForRequest(requestID string, domain string, resolved *ResolvedDest)
PinForRequest stores a resolution result pinned to a specific request.
func (*DNSResolver) ReleaseRequest ¶
func (r *DNSResolver) ReleaseRequest(requestID string)
ReleaseRequest removes all pinned resolutions for a completed request. Should be called when request processing is done to free memory.
func (*DNSResolver) Resolve ¶
func (r *DNSResolver) Resolve(ctx context.Context, domain string, requestID string) (*ResolvedDest, error)
Resolve resolves a domain to IPs with per-request pinning. For a given requestID+domain combination, it always returns the same PinnedIP, even if the underlying DNS record changes (rebinding protection).
type DNSResolverOption ¶
type DNSResolverOption func(*DNSResolver)
DNSResolverOption configures a DNSResolver.
func WithDefaultTTL ¶
func WithDefaultTTL(ttl time.Duration) DNSResolverOption
WithDefaultTTL sets the default cache TTL for resolved entries.
func WithLookupFunc ¶
func WithLookupFunc(fn func(host string) ([]string, error)) DNSResolverOption
WithLookupFunc sets a custom DNS lookup function (useful for testing).
type Decision ¶
type Decision string
Decision represents the outcome of policy evaluation for an action.
type Destination ¶
type Destination struct {
// URL is the full URL if available.
URL string
// Domain is the domain name (e.g., "api.example.com").
Domain string
// IP is the resolved IP address.
IP string
// Port is the port number (0 = unset).
Port int
// Scheme is the protocol scheme (http, https, ws, wss, etc.).
Scheme string
// Path is the URL path or file path.
Path string
// Command is the command name for command_exec actions.
Command string
// CmdArgs are the command arguments for command_exec actions.
CmdArgs []string
}
Destination captures where an action is directed: URL, domain, IP, port, scheme, path, command, and command arguments.
type ExtractOptions ¶
type ExtractOptions struct {
// Base64Decode enables base64 decoding of string values before extraction.
Base64Decode bool
// MaxDepth is the maximum recursion depth (default 10 when 0).
MaxDepth int
}
ExtractOptions configures URL extraction behavior.
type ExtractedURL ¶
type ExtractedURL struct {
// RawValue is the original string value found.
RawValue string
// URL is the parsed full URL (or constructed from IP:port).
URL string
// Domain is the domain name (empty if IP address).
Domain string
// IP is the IP address if directly specified (empty if domain).
IP string
// Port is the port number (0 if not specified, 80/443 inferred from scheme).
Port int
// Scheme is the protocol scheme (http, https, ws, wss, etc.).
Scheme string
// Path is the URL path.
Path string
// Source is the argument key path where found (e.g., "url", "config.endpoint").
Source string
}
ExtractedURL represents a URL or IP:port pattern found in CanonicalAction arguments.
func ExtractURLs ¶
func ExtractURLs(args map[string]interface{}, opts ExtractOptions) []ExtractedURL
ExtractURLs scans a map[string]interface{} (typically CanonicalAction.Arguments) for URLs, IP:port patterns, and URLs embedded in text. It returns all discovered ExtractedURL entries, deduplicated by URL.
type HTTPNormalizer ¶
type HTTPNormalizer struct{}
HTTPNormalizer converts *http.Request to/from CanonicalAction. It maps HTTP requests into the universal CanonicalAction representation so the entire security chain evaluates HTTP requests identically to MCP requests.
func NewHTTPNormalizer ¶
func NewHTTPNormalizer() *HTTPNormalizer
NewHTTPNormalizer creates a new HTTPNormalizer.
func (*HTTPNormalizer) Denormalize ¶
func (n *HTTPNormalizer) Denormalize(action *CanonicalAction, result *InterceptResult) (interface{}, error)
Denormalize converts an InterceptResult back to HTTP response info. For allow decisions, returns the original *http.Request (the proxy handler will forward it). For deny decisions, returns nil and an error with the deny reason.
func (*HTTPNormalizer) Normalize ¶
func (n *HTTPNormalizer) Normalize(ctx context.Context, msg interface{}) (*CanonicalAction, error)
Normalize converts an *http.Request to a CanonicalAction. The msg parameter must be an *http.Request; other types return an error.
func (*HTTPNormalizer) Protocol ¶
func (n *HTTPNormalizer) Protocol() string
Protocol returns "http" indicating this normalizer handles HTTP protocol requests.
type InterceptResult ¶
type InterceptResult struct {
// Decision is the evaluation outcome (allow, deny, approval_required).
Decision Decision
// Reason explains why the decision was made.
Reason string
// RuleID is the identifier of the rule that produced this result.
RuleID string
// RuleName is the human-readable name of the matching rule.
RuleName string
// HelpURL points to documentation about why the action was blocked.
HelpURL string
// HelpText provides inline guidance about the decision.
HelpText string
// Modifications contains optional modifications to the action
// (e.g., argument rewriting, header injection).
Modifications map[string]interface{}
// ApprovalTimeout is how long to wait for human approval.
ApprovalTimeout time.Duration
// ApprovalTimeoutAction is the fallback decision when approval times out.
ApprovalTimeoutAction Decision
}
InterceptResult carries the result of intercepting and evaluating an action.
func (*InterceptResult) IsAllowed ¶
func (r *InterceptResult) IsAllowed() bool
IsAllowed returns true if the decision permits the action to proceed.
type InterceptorChain ¶
type InterceptorChain struct {
// contains filtered or unexported fields
}
InterceptorChain wraps the legacy MessageInterceptor chain with normalize/denormalize. It implements proxy.MessageInterceptor so it can be used as a drop-in replacement in ProxyService without modifying the proxy service code.
Flow: mcp.Message -> MCPNormalizer.Normalize -> ActionInterceptors -> extract mcp.Message from CanonicalAction.OriginalMessage
func NewInterceptorChain ¶
func NewInterceptorChain(normalizer Normalizer, head ActionInterceptor, logger *slog.Logger) *InterceptorChain
NewInterceptorChain creates an InterceptorChain that normalizes incoming mcp.Messages into CanonicalActions, runs them through the ActionInterceptor chain, and extracts the resulting mcp.Message.
type LegacyAdapter ¶
type LegacyAdapter struct {
// contains filtered or unexported fields
}
LegacyAdapter wraps an existing proxy.MessageInterceptor to work with the new ActionInterceptor interface. During migration, each existing interceptor is wrapped in a LegacyAdapter. The adapter: 1. Extracts the original mcp.Message from CanonicalAction.OriginalMessage 2. Calls the legacy interceptor's Intercept(ctx, msg) 3. If the legacy interceptor modified the message, updates CanonicalAction accordingly 4. Returns the CanonicalAction
func NewLegacyAdapter ¶
func NewLegacyAdapter(legacy proxy.MessageInterceptor, name string) *LegacyAdapter
NewLegacyAdapter creates a new LegacyAdapter wrapping the given MessageInterceptor.
func (*LegacyAdapter) Intercept ¶
func (a *LegacyAdapter) Intercept(ctx context.Context, action *CanonicalAction) (*CanonicalAction, error)
Intercept extracts the mcp.Message from the CanonicalAction, calls the legacy interceptor, and syncs any changes back to the CanonicalAction.
func (*LegacyAdapter) Name ¶
func (a *LegacyAdapter) Name() string
Name returns the adapter's name for logging/debugging.
type MCPNormalizer ¶
type MCPNormalizer struct{}
MCPNormalizer converts mcp.Message to/from CanonicalAction. It handles tools/call, sampling/createMessage, and elicitation/create methods, mapping each to the appropriate ActionType.
func NewMCPNormalizer ¶
func NewMCPNormalizer() *MCPNormalizer
NewMCPNormalizer creates a new MCPNormalizer.
func (*MCPNormalizer) Denormalize ¶
func (n *MCPNormalizer) Denormalize(action *CanonicalAction, result *InterceptResult) (interface{}, error)
Denormalize converts an InterceptResult back to a protocol-specific response. For allow decisions, returns the original mcp.Message unchanged. For deny or approval_required decisions, returns nil and an error.
func (*MCPNormalizer) Normalize ¶
func (n *MCPNormalizer) Normalize(ctx context.Context, msg interface{}) (*CanonicalAction, error)
Normalize converts an mcp.Message to a CanonicalAction. The msg parameter must be a *mcp.Message; other types return an error. Non-request messages (responses) are passed through with minimal fields.
func (*MCPNormalizer) Protocol ¶
func (n *MCPNormalizer) Protocol() string
Protocol returns "mcp" indicating this normalizer handles MCP protocol messages.
type MemoryOutboundStore ¶
type MemoryOutboundStore struct {
// contains filtered or unexported fields
}
MemoryOutboundStore implements OutboundRuleStore with thread-safe in-memory storage.
func NewMemoryOutboundStore ¶
func NewMemoryOutboundStore() *MemoryOutboundStore
NewMemoryOutboundStore creates a new empty MemoryOutboundStore.
func (*MemoryOutboundStore) Delete ¶
func (s *MemoryOutboundStore) Delete(_ context.Context, id string) error
Delete removes a rule by ID. Returns ErrOutboundRuleNotFound if not found.
func (*MemoryOutboundStore) Get ¶
func (s *MemoryOutboundStore) Get(_ context.Context, id string) (*OutboundRule, error)
Get returns a copy of the rule with the given ID. Returns ErrOutboundRuleNotFound if the rule does not exist.
func (*MemoryOutboundStore) List ¶
func (s *MemoryOutboundStore) List(_ context.Context) ([]OutboundRule, error)
List returns all rules as copies, sorted by Priority ascending. Both enabled and disabled rules are returned.
func (*MemoryOutboundStore) Save ¶
func (s *MemoryOutboundStore) Save(_ context.Context, rule *OutboundRule) error
Save creates or updates a rule. Stores a deep copy so external modifications do not affect stored data.
type Normalizer ¶
type Normalizer interface {
// Normalize converts a protocol-specific message to a CanonicalAction.
// The original message is stored in CanonicalAction.OriginalMessage
// for denormalization on the response path.
Normalize(ctx context.Context, msg interface{}) (*CanonicalAction, error)
// Denormalize converts an InterceptResult back to a protocol-specific response.
// Uses CanonicalAction.OriginalMessage to construct the response.
// For allow decisions, returns the original message.
// For deny decisions, returns nil and an error describing the denial.
Denormalize(action *CanonicalAction, result *InterceptResult) (interface{}, error)
// Protocol returns the protocol name this normalizer handles (e.g., "mcp").
Protocol() string
}
Normalizer converts between protocol-specific messages and CanonicalAction. Each protocol (MCP, HTTP, WebSocket, runtime) has its own Normalizer implementation that knows how to extract WHO/WHAT/WHERE/HOW/CONTEXT fields from its native message format.
type OutboundDenyError ¶
type OutboundDenyError struct {
Domain string
IP string
Port int
RuleName string
HelpText string
HelpURL string
Reason string
}
OutboundDenyError provides structured deny information for outbound blocks.
func (*OutboundDenyError) Error ¶
func (e *OutboundDenyError) Error() string
Error implements the error interface.
func (*OutboundDenyError) Unwrap ¶
func (e *OutboundDenyError) Unwrap() error
Unwrap returns the sentinel error for errors.Is() support.
type OutboundInterceptor ¶
type OutboundInterceptor struct {
// contains filtered or unexported fields
}
OutboundInterceptor extracts URLs from action arguments, resolves DNS, evaluates against outbound rules, and blocks denied destinations. It populates action.Destination fields so that downstream CEL policy evaluation can use dest_* variables.
Rules are stored via an atomic pointer for lock-free reads during the hot path. The SetRules method enables dynamic rule replacement without locking the interceptor.
func NewOutboundInterceptor ¶
func NewOutboundInterceptor(rules []OutboundRule, resolver *DNSResolver, next ActionInterceptor, logger *slog.Logger) *OutboundInterceptor
NewOutboundInterceptor creates a new OutboundInterceptor. The initial rules are stored via atomic pointer. nil is treated as empty.
func (*OutboundInterceptor) Intercept ¶
func (o *OutboundInterceptor) Intercept(ctx context.Context, a *CanonicalAction) (*CanonicalAction, error)
Intercept processes a CanonicalAction by extracting URLs, resolving DNS, evaluating outbound rules, and populating Destination fields.
func (*OutboundInterceptor) SetRules ¶
func (o *OutboundInterceptor) SetRules(rules []OutboundRule)
SetRules atomically replaces the interceptor's rules with the provided set. Rules are sorted by Priority ascending before storage. This enables the admin service to reload rules without locking the interceptor's hot path.
type OutboundRule ¶
type OutboundRule struct {
// ID uniquely identifies this rule.
ID string
// Name is the human-readable rule name.
Name string
// Mode is blocklist or allowlist.
Mode RuleMode
// Targets are the target specifications for this rule.
Targets []OutboundTarget
// Action is what happens when the rule matches (block, alert, log).
Action RuleAction
// Scope is empty for global rules, otherwise a scope identifier (Phase 4).
Scope string
// Priority determines evaluation order (lower = higher priority).
Priority int
// Enabled controls whether this rule is active.
Enabled bool
// Base64Scan enables base64 URL decoding in URL extraction (OUT-04).
Base64Scan bool
// HelpText is shown in deny messages (OUT-10).
HelpText string
// HelpURL is a link shown in deny messages (OUT-10).
HelpURL string
// ReadOnly is true for default blocklist rules that cannot be modified or deleted.
ReadOnly bool
// CreatedAt is when this rule was created.
CreatedAt time.Time
// UpdatedAt is when this rule was last modified.
UpdatedAt time.Time
}
OutboundRule defines a rule for controlling outbound network access.
func DefaultBlocklistRules ¶
func DefaultBlocklistRules() []OutboundRule
DefaultBlocklistRules returns the default outbound blocklist rules active on a fresh SentinelGate installation. These rules block common data exfiltration channels and access to private/internal networks.
func EvaluateDestination ¶
func EvaluateDestination(rules []OutboundRule, domain, ip string, port int, logger *slog.Logger) (bool, *OutboundRule)
evaluateDestination checks a destination against the given outbound rules, grouping by scope and evaluating by mode. Returns (true, rule) if blocked, (false, nil) if allowed. For blocklist rules with action "alert" or "log", the match is logged but the destination is not blocked.
type OutboundRuleStore ¶
type OutboundRuleStore interface {
// List returns all rules sorted by Priority ascending.
List(ctx context.Context) ([]OutboundRule, error)
// Get returns a single rule by ID. Returns ErrOutboundRuleNotFound if not found.
Get(ctx context.Context, id string) (*OutboundRule, error)
// Save creates or updates a rule in the store.
Save(ctx context.Context, rule *OutboundRule) error
// Delete removes a rule by ID. Returns ErrOutboundRuleNotFound if not found.
Delete(ctx context.Context, id string) error
}
OutboundRuleStore defines CRUD operations for outbound rules.
type OutboundTarget ¶
type OutboundTarget struct {
// Type is the kind of target (domain, ip, cidr, domain_glob, port_range).
Type TargetType
// Value is the target value (e.g., "evil.com", "10.0.0.0/8", "*.ngrok.io", "1-1024").
Value string
}
OutboundTarget represents a single target specification in an outbound rule.
type PendingApproval ¶
type PendingApproval struct {
ID string `json:"id"`
ToolName string `json:"tool_name"`
Arguments map[string]interface{} `json:"arguments,omitempty"`
IdentityName string `json:"identity_name"`
IdentityID string `json:"identity_id"`
Status string `json:"status"` // "pending", "approved", "denied", "timed_out"
CreatedAt time.Time `json:"created_at"`
Timeout time.Duration `json:"-"`
TimeoutAction policy.Action `json:"-"`
// contains filtered or unexported fields
}
PendingApproval represents a tool call that is blocked pending human approval.
type PolicyActionInterceptor ¶
type PolicyActionInterceptor struct {
// contains filtered or unexported fields
}
PolicyActionInterceptor evaluates CanonicalActions against RBAC policies. This is the natively migrated version of proxy.PolicyInterceptor -- it operates directly on CanonicalAction instead of going through LegacyAdapter. It proves the CANON-10 migration path: each interceptor can be individually rewritten to use CanonicalAction fields directly.
func NewPolicyActionInterceptor ¶
func NewPolicyActionInterceptor(engine policy.PolicyEngine, next ActionInterceptor, logger *slog.Logger) *PolicyActionInterceptor
NewPolicyActionInterceptor creates a new PolicyActionInterceptor.
func (*PolicyActionInterceptor) Intercept ¶
func (p *PolicyActionInterceptor) Intercept(ctx context.Context, action *CanonicalAction) (*CanonicalAction, error)
Intercept evaluates tool calls and HTTP requests against policies before passing to the next interceptor. Other action types pass through without policy evaluation.
type QuarantineChecker ¶
QuarantineChecker is satisfied by ToolSecurityService.
type QuarantineInterceptor ¶
type QuarantineInterceptor struct {
// contains filtered or unexported fields
}
QuarantineInterceptor blocks calls to quarantined tools. It sits before the PolicyActionInterceptor in the chain so that quarantined tools are immediately rejected regardless of policy.
func NewQuarantineInterceptor ¶
func NewQuarantineInterceptor(checker QuarantineChecker, next ActionInterceptor, logger *slog.Logger) *QuarantineInterceptor
NewQuarantineInterceptor creates a QuarantineInterceptor.
func (*QuarantineInterceptor) Intercept ¶
func (q *QuarantineInterceptor) Intercept(ctx context.Context, act *CanonicalAction) (*CanonicalAction, error)
Intercept blocks quarantined tool calls, passes everything else through.
type ResolvedDest ¶
type ResolvedDest struct {
// Domain is the original domain that was resolved.
Domain string
// IPs contains all resolved IP addresses.
IPs []string
// PinnedIP is the first resolved IP, pinned for the request lifetime
// to prevent DNS rebinding attacks.
PinnedIP string
// CachedAt is when this resolution was cached.
CachedAt time.Time
// TTL is how long this cache entry is valid.
TTL time.Duration
}
ResolvedDest holds the result of a DNS resolution, including all resolved IPs and the pinned IP for a specific request.
type ResponseScanInterceptor ¶
type ResponseScanInterceptor struct {
// contains filtered or unexported fields
}
ResponseScanInterceptor scans MCP tool results for prompt injection before forwarding them to the agent. It implements ActionInterceptor and sits between the upstream router and the policy interceptor in the chain.
In monitor mode, detections are logged but responses pass through. In enforce mode, responses containing injection patterns are blocked.
func NewResponseScanInterceptor ¶
func NewResponseScanInterceptor( scanner *ResponseScanner, next ActionInterceptor, mode ScanMode, enabled bool, logger *slog.Logger, ) *ResponseScanInterceptor
NewResponseScanInterceptor creates a new ResponseScanInterceptor.
func (*ResponseScanInterceptor) Enabled ¶
func (r *ResponseScanInterceptor) Enabled() bool
Enabled returns whether scanning is currently active.
func (*ResponseScanInterceptor) Intercept ¶
func (r *ResponseScanInterceptor) Intercept(ctx context.Context, a *CanonicalAction) (*CanonicalAction, error)
Intercept processes a CanonicalAction through the chain and scans server-to-client responses for prompt injection.
func (*ResponseScanInterceptor) Mode ¶
func (r *ResponseScanInterceptor) Mode() ScanMode
Mode returns the current scan mode.
func (*ResponseScanInterceptor) SetEnabled ¶
func (r *ResponseScanInterceptor) SetEnabled(enabled bool)
SetEnabled updates the enabled state thread-safely.
func (*ResponseScanInterceptor) SetMode ¶
func (r *ResponseScanInterceptor) SetMode(mode ScanMode)
SetMode updates the scan mode thread-safely.
type ResponseScanner ¶
type ResponseScanner struct {
// contains filtered or unexported fields
}
ResponseScanner detects prompt injection patterns in MCP tool results. All patterns are compiled at construction time for minimal per-scan overhead.
func NewResponseScanner ¶
func NewResponseScanner() *ResponseScanner
NewResponseScanner creates a ResponseScanner with compiled regex patterns for detecting prompt injection attacks in tool responses.
func (*ResponseScanner) Scan ¶
func (s *ResponseScanner) Scan(content string) ScanResult
Scan runs all compiled patterns against the given content string. Returns a ScanResult with any findings. Empty content returns immediately with no findings.
func (*ResponseScanner) ScanJSON ¶
func (s *ResponseScanner) ScanJSON(v interface{}) ScanResult
ScanJSON recursively scans JSON-compatible values (strings, maps, slices) for prompt injection patterns. This handles the common case where MCP tool results are JSON objects with string fields that may contain injected content.
type RuleAction ¶
type RuleAction string
RuleAction determines the action to take when a rule matches.
const ( // RuleActionBlock blocks the action entirely. RuleActionBlock RuleAction = "block" // RuleActionAlert allows the action but raises an alert. RuleActionAlert RuleAction = "alert" // RuleActionLog allows the action but logs it. RuleActionLog RuleAction = "log" )
type RuleMode ¶
type RuleMode string
RuleMode determines whether a rule operates as a blocklist or allowlist.
type ScanFinding ¶
type ScanFinding struct {
// PatternName is the identifier of the matched pattern (e.g., "system_prompt_override").
PatternName string
// PatternCategory groups related patterns (e.g., "prompt_injection", "delimiter_escape").
PatternCategory string
// MatchedText is the text that matched, truncated to 100 characters.
MatchedText string
// Position is the byte offset where the match starts in the scanned content.
Position int
}
ScanFinding represents a single pattern match found during scanning.
type ScanResult ¶
type ScanResult struct {
// Detected is true if one or more patterns matched.
Detected bool
// Findings contains all pattern matches found.
Findings []ScanFinding
// ScanDurationNs is how long the scan took in nanoseconds.
ScanDurationNs int64
}
ScanResult contains the outcome of scanning content for prompt injection.
type TargetType ¶
type TargetType string
TargetType categorizes the kind of target in an outbound rule.
const ( // TargetDomain matches an exact domain name. TargetDomain TargetType = "domain" // TargetIP matches an exact IP address. TargetIP TargetType = "ip" // TargetCIDR matches an IP within a CIDR range. TargetCIDR TargetType = "cidr" // TargetDomainGlob matches a domain against a glob pattern, including subdomains. TargetDomainGlob TargetType = "domain_glob" // TargetPortRange matches a port within a numeric range. TargetPortRange TargetType = "port_range" )
Source Files
¶
- approval_interceptor.go
- chain.go
- default_blocklist.go
- dns_resolver.go
- http_normalizer.go
- interceptor.go
- legacy_adapter.go
- mcp_normalizer.go
- normalizer.go
- outbound_interceptor.go
- outbound_store.go
- outbound_types.go
- policy_action_interceptor.go
- quarantine_interceptor.go
- response_scan_interceptor.go
- response_scanner.go
- types.go
- url_extractor.go