actshield 0.9.0__py3-none-any.whl
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.
- actshield/__init__.py +439 -0
- actshield/__main__.py +46 -0
- actshield/agents/__init__.py +12 -0
- actshield/agents/agent.py +200 -0
- actshield/agents/identity.py +114 -0
- actshield/api/__init__.py +34 -0
- actshield/api/models.py +198 -0
- actshield/api/server.py +669 -0
- actshield/api/service.py +599 -0
- actshield/approval/__init__.py +15 -0
- actshield/approval/approval.py +164 -0
- actshield/cli/__init__.py +8 -0
- actshield/cli/graph.py +49 -0
- actshield/cli/main.py +802 -0
- actshield/cli/shell.py +406 -0
- actshield/cli/theme.py +110 -0
- actshield/client.py +757 -0
- actshield/config.py +88 -0
- actshield/context/__init__.py +14 -0
- actshield/context/context.py +161 -0
- actshield/context/provenance.py +108 -0
- actshield/context/taint.py +48 -0
- actshield/decisions/decision.py +74 -0
- actshield/delegation/__init__.py +11 -0
- actshield/delegation/authority.py +63 -0
- actshield/delegation/delegation.py +180 -0
- actshield/demo.py +139 -0
- actshield/doctor.py +94 -0
- actshield/drift/__init__.py +27 -0
- actshield/drift/drift_engine.py +149 -0
- actshield/drift/drift_models.py +63 -0
- actshield/evaluation/__init__.py +1 -0
- actshield/evaluation/cases/__init__.py +1 -0
- actshield/evaluation/eval_suite.py +254 -0
- actshield/forensics/__init__.py +53 -0
- actshield/forensics/access_graph.py +216 -0
- actshield/forensics/authority_graph.py +186 -0
- actshield/forensics/delegation_graph.py +119 -0
- actshield/forensics/explanation.py +254 -0
- actshield/forensics/models.py +488 -0
- actshield/forensics/queries.py +367 -0
- actshield/forensics/serializers.py +68 -0
- actshield/forensics/service.py +310 -0
- actshield/forensics/snapshots.py +174 -0
- actshield/gates/__init__.py +13 -0
- actshield/gates/gate_models.py +46 -0
- actshield/gates/security_gate.py +191 -0
- actshield/gateway/__init__.py +13 -0
- actshield/gateway/http.py +191 -0
- actshield/gateway/mcp.py +292 -0
- actshield/incidents/__init__.py +25 -0
- actshield/incidents/incident.py +94 -0
- actshield/incidents/incident_engine.py +163 -0
- actshield/incidents/incident_rules.py +116 -0
- actshield/incidents/incident_state.py +58 -0
- actshield/integrations/__init__.py +24 -0
- actshield/integrations/ai_secura.py +169 -0
- actshield/integrations/ai_secura_analysis.py +236 -0
- actshield/integrations/apiris.py +122 -0
- actshield/integrations/few_shot.py +104 -0
- actshield/integrations/ollama_adapter.py +538 -0
- actshield/integrations/prompts/__init__.py +1 -0
- actshield/integrations/prompts/examples/__init__.py +1 -0
- actshield/integrations/security_packet.py +82 -0
- actshield/llm_config.py +89 -0
- actshield/offensive/__init__.py +95 -0
- actshield/offensive/adaptive/__init__.py +22 -0
- actshield/offensive/adaptive/adaptive_engine.py +165 -0
- actshield/offensive/adaptive/attack_selector.py +51 -0
- actshield/offensive/adaptive/boundary_search.py +99 -0
- actshield/offensive/adaptive/campaign_memory.py +123 -0
- actshield/offensive/adaptive/feedback.py +84 -0
- actshield/offensive/adaptive/mutation_planner.py +57 -0
- actshield/offensive/attack.py +78 -0
- actshield/offensive/campaign.py +219 -0
- actshield/offensive/corpus.py +155 -0
- actshield/offensive/engine.py +466 -0
- actshield/offensive/evaluator.py +116 -0
- actshield/offensive/evidence.py +63 -0
- actshield/offensive/generator.py +128 -0
- actshield/offensive/mutation.py +101 -0
- actshield/offensive/results.py +77 -0
- actshield/offensive/safety.py +80 -0
- actshield/offensive/strategies/__init__.py +22 -0
- actshield/offensive/strategies/authority_escalation.py +100 -0
- actshield/offensive/strategies/base.py +34 -0
- actshield/offensive/strategies/context_manipulation.py +100 -0
- actshield/offensive/strategies/data_exfiltration.py +100 -0
- actshield/offensive/strategies/delegation_attacks.py +100 -0
- actshield/offensive/strategies/mcp_attacks.py +100 -0
- actshield/offensive/strategies/prompt_injection.py +100 -0
- actshield/offensive/strategies/tool_poisoning.py +100 -0
- actshield/offensive/target.py +113 -0
- actshield/offensive/vulnerable_target.py +121 -0
- actshield/persistence/__init__.py +18 -0
- actshield/persistence/siem.py +102 -0
- actshield/persistence/storage.py +240 -0
- actshield/policy/__init__.py +12 -0
- actshield/policy/evaluator.py +294 -0
- actshield/policy/intent.py +113 -0
- actshield/policy/policy.py +48 -0
- actshield/posture/__init__.py +26 -0
- actshield/posture/posture_engine.py +186 -0
- actshield/posture/posture_models.py +152 -0
- actshield/posture/posture_rules.py +137 -0
- actshield/providers/__init__.py +32 -0
- actshield/providers/anthropic_provider.py +146 -0
- actshield/providers/base.py +160 -0
- actshield/providers/gemini_provider.py +133 -0
- actshield/providers/null_provider.py +40 -0
- actshield/providers/ollama_provider.py +135 -0
- actshield/providers/openai_provider.py +142 -0
- actshield/providers/registry.py +244 -0
- actshield/py.typed +0 -0
- actshield/response/__init__.py +14 -0
- actshield/response/response_actions.py +39 -0
- actshield/response/response_audit.py +32 -0
- actshield/response/response_engine.py +139 -0
- actshield/risk/models.py +104 -0
- actshield/serve.py +117 -0
- actshield/static/404.html +1 -0
- actshield/static/__next.__PAGE__.txt +24 -0
- actshield/static/__next._full.txt +20 -0
- actshield/static/__next._tree.txt +4 -0
- actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_buildManifest.js +11 -0
- actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_clientMiddlewareManifest.js +1 -0
- actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_ssgManifest.js +1 -0
- actshield/static/_next/static/chunks/09kny2eqjc2or.js +1 -0
- actshield/static/_next/static/chunks/0c1zba1u9whdp.js +1 -0
- actshield/static/_next/static/chunks/0cz1d0mv5g_q7.js +1 -0
- actshield/static/_next/static/chunks/0dbjjeg01x25o.js +1 -0
- actshield/static/_next/static/chunks/0duobs55ne238.js +1 -0
- actshield/static/_next/static/chunks/0iaz41l6068e4.js +1 -0
- actshield/static/_next/static/chunks/0mjhyv72x2idp.js +1 -0
- actshield/static/_next/static/chunks/0nelpqfu_ciq6.js +1 -0
- actshield/static/_next/static/chunks/0p1bci9ch797v.js +1 -0
- actshield/static/_next/static/chunks/0tld_ygho5tgm.js +1 -0
- actshield/static/_next/static/chunks/0w1-y7oni66j9.js +1 -0
- actshield/static/_next/static/chunks/10537zyl427zj.js +1 -0
- actshield/static/_next/static/chunks/11pc_jkl3aggn.js +1 -0
- actshield/static/_next/static/chunks/16k7nw0b3t8ys.js +1 -0
- actshield/static/_next/static/chunks/19mx3mg6lkumu.js +1 -0
- actshield/static/_next/static/chunks/1_8p47b-kxg2a.js +1 -0
- actshield/static/_next/static/chunks/1dszjozwfqegx.js +1 -0
- actshield/static/_next/static/chunks/1h43jcb90-m2r.js +22 -0
- actshield/static/_next/static/chunks/1ly04cvt_wh_j.js +1 -0
- actshield/static/_next/static/chunks/1odxrypuwuwp_.js +1 -0
- actshield/static/_next/static/chunks/1oes4c35qz5ku.js +1 -0
- actshield/static/_next/static/chunks/1ow883jl4ln-r.js +16 -0
- actshield/static/_next/static/chunks/1po7bna1as8tc.js +1 -0
- actshield/static/_next/static/chunks/1rsh0og8ifkzx.js +1 -0
- actshield/static/_next/static/chunks/1v0lwzv-859z_.js +1 -0
- actshield/static/_next/static/chunks/25iat2epwx25a.js +1 -0
- actshield/static/_next/static/chunks/25uvt4s2f39a4.js +1 -0
- actshield/static/_next/static/chunks/27t_qfc-3_lzs.js +1 -0
- actshield/static/_next/static/chunks/28bkmy8mez7gm.js +1 -0
- actshield/static/_next/static/chunks/2b6brmw_drw1p.js +1 -0
- actshield/static/_next/static/chunks/2fnhtxi4j6vge.js +1 -0
- actshield/static/_next/static/chunks/2p087eftxemg4.js +6 -0
- actshield/static/_next/static/chunks/2s8pao_z8pgtq.js +1 -0
- actshield/static/_next/static/chunks/2yj7ooc2c-zpg.js +1 -0
- actshield/static/_next/static/chunks/3-mrrr8udt5tk.js +1 -0
- actshield/static/_next/static/chunks/310vm2bl3xxpt.js +31 -0
- actshield/static/_next/static/chunks/35mvsv251jx1r.css +3 -0
- actshield/static/_next/static/chunks/370vf0oetlsx9.js +1 -0
- actshield/static/_next/static/chunks/3e-2m72tyo556.js +1 -0
- actshield/static/_next/static/chunks/3fntmmi971322.js +1 -0
- actshield/static/_next/static/chunks/3fzw-g0hycl2c.js +1 -0
- actshield/static/_next/static/chunks/3lopq3lhmcjxg.js +129 -0
- actshield/static/_next/static/chunks/3mpe2jejel0v2.css +1 -0
- actshield/static/_next/static/chunks/3t8o4f2lzr2sf.js +1 -0
- actshield/static/_next/static/chunks/3y-v1neyllne5.js +1 -0
- actshield/static/_next/static/chunks/43oiwy8mx6cs1.js +1 -0
- actshield/static/_next/static/chunks/turbopack-23wzuebcy_lxm.js +1 -0
- actshield/static/_next/static/media/1bffadaabf893a1e-s.3-6t-g6q0vh0a.woff2 +0 -0
- actshield/static/_next/static/media/2bbe8d2671613f1f-s.0k62hbripvv8p.woff2 +0 -0
- actshield/static/_next/static/media/2c55a0e60120577a-s.0-dom-5bn10r2.woff2 +0 -0
- actshield/static/_next/static/media/5476f68d60460930-s.2uwcyprjm3xu3.woff2 +0 -0
- actshield/static/_next/static/media/83afe278b6a6bb3c-s.p.2bn3s6zvc0dyp.woff2 +0 -0
- actshield/static/_next/static/media/9c72aa0f40e4eef8-s.1y4-pdgsjb-pw.woff2 +0 -0
- actshield/static/_next/static/media/ad66f9afd8947f86-s.3lvt2whj97whp.woff2 +0 -0
- actshield/static/_next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- actshield/static/_not-found/__next._full.txt +17 -0
- actshield/static/_not-found/__next._not-found/__PAGE__.txt +23 -0
- actshield/static/_not-found/__next._tree.txt +3 -0
- actshield/static/_not-found.html +1 -0
- actshield/static/_not-found.txt +17 -0
- actshield/static/access/matrix/__next._full.txt +24 -0
- actshield/static/access/matrix/__next._tree.txt +4 -0
- actshield/static/access/matrix/__next.access/matrix/__PAGE__.txt +30 -0
- actshield/static/access/matrix.html +1 -0
- actshield/static/access/matrix.txt +24 -0
- actshield/static/activity/__next._full.txt +22 -0
- actshield/static/activity/__next._tree.txt +4 -0
- actshield/static/activity/__next.activity/__PAGE__.txt +27 -0
- actshield/static/activity.html +1 -0
- actshield/static/activity.txt +22 -0
- actshield/static/agents/__next._full.txt +22 -0
- actshield/static/agents/__next._tree.txt +4 -0
- actshield/static/agents/__next.agents/__PAGE__.txt +27 -0
- actshield/static/agents.html +1 -0
- actshield/static/agents.txt +22 -0
- actshield/static/ai-secura/__next._full.txt +22 -0
- actshield/static/ai-secura/__next._tree.txt +4 -0
- actshield/static/ai-secura/__next.ai-secura/__PAGE__.txt +27 -0
- actshield/static/ai-secura.html +1 -0
- actshield/static/ai-secura.txt +22 -0
- actshield/static/api/__next._full.txt +22 -0
- actshield/static/api/__next._tree.txt +4 -0
- actshield/static/api/__next.api/__PAGE__.txt +27 -0
- actshield/static/api.html +15 -0
- actshield/static/api.txt +22 -0
- actshield/static/apiris/__next._full.txt +22 -0
- actshield/static/apiris/__next._tree.txt +4 -0
- actshield/static/apiris/__next.apiris/__PAGE__.txt +27 -0
- actshield/static/apiris.html +1 -0
- actshield/static/apiris.txt +22 -0
- actshield/static/attack-graph/__next._full.txt +23 -0
- actshield/static/attack-graph/__next._tree.txt +5 -0
- actshield/static/attack-graph/__next.attack-graph/__PAGE__.txt +28 -0
- actshield/static/attack-graph.html +2 -0
- actshield/static/attack-graph.txt +23 -0
- actshield/static/campaigns/__next._full.txt +22 -0
- actshield/static/campaigns/__next._tree.txt +4 -0
- actshield/static/campaigns/__next.campaigns/__PAGE__.txt +27 -0
- actshield/static/campaigns.html +1 -0
- actshield/static/campaigns.txt +22 -0
- actshield/static/context/__next._full.txt +22 -0
- actshield/static/context/__next._tree.txt +4 -0
- actshield/static/context/__next.context/__PAGE__.txt +27 -0
- actshield/static/context.html +1 -0
- actshield/static/context.txt +22 -0
- actshield/static/dashboard/__next._full.txt +22 -0
- actshield/static/dashboard/__next._tree.txt +4 -0
- actshield/static/dashboard/__next.dashboard/__PAGE__.txt +27 -0
- actshield/static/dashboard.html +1 -0
- actshield/static/dashboard.txt +22 -0
- actshield/static/delegations/__next._full.txt +22 -0
- actshield/static/delegations/__next._tree.txt +4 -0
- actshield/static/delegations/__next.delegations/__PAGE__.txt +27 -0
- actshield/static/delegations.html +1 -0
- actshield/static/delegations.txt +22 -0
- actshield/static/demo/__next._full.txt +22 -0
- actshield/static/demo/__next._tree.txt +4 -0
- actshield/static/demo/__next.demo/__PAGE__.txt +27 -0
- actshield/static/demo.html +1 -0
- actshield/static/demo.txt +22 -0
- actshield/static/drift/__next._full.txt +22 -0
- actshield/static/drift/__next._tree.txt +4 -0
- actshield/static/drift/__next.drift/__PAGE__.txt +27 -0
- actshield/static/drift.html +1 -0
- actshield/static/drift.txt +22 -0
- actshield/static/favicon.ico +0 -0
- actshield/static/file.svg +1 -0
- actshield/static/forensics/__next._full.txt +22 -0
- actshield/static/forensics/__next._tree.txt +4 -0
- actshield/static/forensics/__next.forensics/__PAGE__.txt +27 -0
- actshield/static/forensics.html +1 -0
- actshield/static/forensics.txt +22 -0
- actshield/static/globe.svg +1 -0
- actshield/static/incidents/__next._full.txt +22 -0
- actshield/static/incidents/__next._tree.txt +4 -0
- actshield/static/incidents/__next.incidents/__PAGE__.txt +27 -0
- actshield/static/incidents.html +1 -0
- actshield/static/incidents.txt +22 -0
- actshield/static/index.html +3 -0
- actshield/static/index.txt +20 -0
- actshield/static/logo.png +0 -0
- actshield/static/metrics/__next._full.txt +22 -0
- actshield/static/metrics/__next._tree.txt +4 -0
- actshield/static/metrics/__next.metrics/__PAGE__.txt +27 -0
- actshield/static/metrics.html +1 -0
- actshield/static/metrics.txt +22 -0
- actshield/static/next.svg +1 -0
- actshield/static/offensive/__next._full.txt +22 -0
- actshield/static/offensive/__next._tree.txt +4 -0
- actshield/static/offensive/__next.offensive/__PAGE__.txt +27 -0
- actshield/static/offensive.html +1 -0
- actshield/static/offensive.txt +22 -0
- actshield/static/policies/__next._full.txt +22 -0
- actshield/static/policies/__next._tree.txt +4 -0
- actshield/static/policies/__next.policies/__PAGE__.txt +27 -0
- actshield/static/policies.html +1 -0
- actshield/static/policies.txt +22 -0
- actshield/static/posture/__next._full.txt +22 -0
- actshield/static/posture/__next._tree.txt +4 -0
- actshield/static/posture/__next.posture/__PAGE__.txt +27 -0
- actshield/static/posture.html +1 -0
- actshield/static/posture.txt +22 -0
- actshield/static/regressions/__next._full.txt +22 -0
- actshield/static/regressions/__next._tree.txt +4 -0
- actshield/static/regressions/__next.regressions/__PAGE__.txt +27 -0
- actshield/static/regressions.html +1 -0
- actshield/static/regressions.txt +22 -0
- actshield/static/reports/__next._full.txt +22 -0
- actshield/static/reports/__next._tree.txt +4 -0
- actshield/static/reports/__next.reports/__PAGE__.txt +27 -0
- actshield/static/reports.html +1 -0
- actshield/static/reports.txt +22 -0
- actshield/static/resources/__next._full.txt +22 -0
- actshield/static/resources/__next._tree.txt +4 -0
- actshield/static/resources/__next.resources/__PAGE__.txt +27 -0
- actshield/static/resources.html +1 -0
- actshield/static/resources.txt +22 -0
- actshield/static/security-gates/__next._full.txt +22 -0
- actshield/static/security-gates/__next._tree.txt +4 -0
- actshield/static/security-gates/__next.security-gates/__PAGE__.txt +27 -0
- actshield/static/security-gates.html +1 -0
- actshield/static/security-gates.txt +22 -0
- actshield/static/settings/__next._full.txt +22 -0
- actshield/static/settings/__next._tree.txt +4 -0
- actshield/static/settings/__next.settings/__PAGE__.txt +27 -0
- actshield/static/settings.html +1 -0
- actshield/static/settings.txt +22 -0
- actshield/static/tasks/__next._full.txt +22 -0
- actshield/static/tasks/__next._tree.txt +4 -0
- actshield/static/tasks/__next.tasks/__PAGE__.txt +27 -0
- actshield/static/tasks.html +1 -0
- actshield/static/tasks.txt +22 -0
- actshield/static/threats/__next._full.txt +22 -0
- actshield/static/threats/__next._tree.txt +4 -0
- actshield/static/threats/__next.threats/__PAGE__.txt +27 -0
- actshield/static/threats.html +1 -0
- actshield/static/threats.txt +22 -0
- actshield/static/tools/__next._full.txt +22 -0
- actshield/static/tools/__next._tree.txt +4 -0
- actshield/static/tools/__next.tools/__PAGE__.txt +27 -0
- actshield/static/tools.html +1 -0
- actshield/static/tools.txt +22 -0
- actshield/static/traces/__next._full.txt +22 -0
- actshield/static/traces/__next._tree.txt +4 -0
- actshield/static/traces/__next.traces/__PAGE__.txt +27 -0
- actshield/static/traces.html +1 -0
- actshield/static/traces.txt +22 -0
- actshield/static/vercel.svg +1 -0
- actshield/static/window.svg +1 -0
- actshield/tasks/__init__.py +6 -0
- actshield/tasks/task.py +143 -0
- actshield/threatmodel/__init__.py +70 -0
- actshield/threatmodel/actors.py +210 -0
- actshield/threatmodel/analyzer.py +131 -0
- actshield/threatmodel/assets.py +167 -0
- actshield/threatmodel/boundaries.py +165 -0
- actshield/threatmodel/exporters.py +49 -0
- actshield/threatmodel/mitigations.py +209 -0
- actshield/threatmodel/models.py +80 -0
- actshield/threatmodel/report.py +341 -0
- actshield/threatmodel/scenarios.py +212 -0
- actshield/threatmodel/scoring.py +66 -0
- actshield/threatmodel/threats.py +387 -0
- actshield/tools/__init__.py +20 -0
- actshield/tools/interceptor.py +256 -0
- actshield/tools/tool.py +71 -0
- actshield/tracing/__init__.py +38 -0
- actshield/tracing/correlation.py +173 -0
- actshield/tracing/events.py +75 -0
- actshield/tracing/tracer.py +305 -0
- actshield/watch.py +129 -0
- actshield-0.9.0.dist-info/METADATA +57 -0
- actshield-0.9.0.dist-info/RECORD +366 -0
- actshield-0.9.0.dist-info/WHEEL +5 -0
- actshield-0.9.0.dist-info/entry_points.txt +4 -0
- actshield-0.9.0.dist-info/top_level.txt +2 -0
- agentguard/__init__.py +39 -0
- agentguard/__main__.py +8 -0
- agentguard/py.typed +1 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Threat actors — who can attack the agent system and how."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ActorType(str, Enum):
|
|
11
|
+
"""Classification of threat actor origin."""
|
|
12
|
+
EXTERNAL_ATTACKER = "EXTERNAL_ATTACKER"
|
|
13
|
+
MALICIOUS_USER = "MALICIOUS_USER"
|
|
14
|
+
COMPROMISED_AGENT = "COMPROMISED_AGENT"
|
|
15
|
+
MALICIOUS_MCP_SERVER = "MALICIOUS_MCP_SERVER"
|
|
16
|
+
POISONED_DOCUMENT = "POISONED_DOCUMENT"
|
|
17
|
+
POISONED_RAG_SOURCE = "POISONED_RAG_SOURCE"
|
|
18
|
+
COMPROMISED_TOOL = "COMPROMISED_TOOL"
|
|
19
|
+
SUPPLY_CHAIN_ATTACKER = "SUPPLY_CHAIN_ATTACKER"
|
|
20
|
+
INSIDER_THREAT = "INSIDER_THREAT"
|
|
21
|
+
PROMPT_INJECTOR = "PROMPT_INJECTOR"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ActorCapability(str, Enum):
|
|
25
|
+
"""What the actor is capable of doing."""
|
|
26
|
+
CRAFT_PROMPTS = "CRAFT_PROMPTS"
|
|
27
|
+
INJECT_CONTEXT = "INJECT_CONTEXT"
|
|
28
|
+
POISON_DOCUMENTS = "POISON_DOCUMENTS"
|
|
29
|
+
INTERCEPT_RESPONSES = "INTERCEPT_RESPONSES"
|
|
30
|
+
COMPROMISE_TOOLS = "COMPROMISE_TOOLS"
|
|
31
|
+
IMPERSONATE_AGENT = "IMPERSONATE_AGENT"
|
|
32
|
+
EXFILTRATE_DATA = "EXFILTRATE_DATA"
|
|
33
|
+
ESCALATE_PRIVILEGES = "ESCALATE_PRIVILEGES"
|
|
34
|
+
MANIPULATE_DELEGATION = "MANIPULATE_DELEGATION"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ThreatActor(BaseModel):
|
|
38
|
+
"""A threat actor that can attack the agent system."""
|
|
39
|
+
actor_id: str
|
|
40
|
+
name: str
|
|
41
|
+
actor_type: ActorType
|
|
42
|
+
description: str
|
|
43
|
+
capabilities: list[ActorCapability] = Field(default_factory=list)
|
|
44
|
+
entry_points: list[str] = Field(default_factory=list)
|
|
45
|
+
# MITRE ATT&CK-style sophistication: 1 (script kiddie) to 5 (nation-state)
|
|
46
|
+
sophistication: int = 2
|
|
47
|
+
# Is this actor already inside the trust boundary?
|
|
48
|
+
is_internal: bool = False
|
|
49
|
+
|
|
50
|
+
def to_dict(self) -> dict[str, Any]:
|
|
51
|
+
return self.model_dump(mode="json")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ActorRegistry:
|
|
55
|
+
"""Catalog of threat actors relevant to autonomous AI systems."""
|
|
56
|
+
|
|
57
|
+
_DEFAULTS: list[dict[str, Any]] = [
|
|
58
|
+
{
|
|
59
|
+
"actor_id": "act_ext_attacker",
|
|
60
|
+
"name": "External Attacker",
|
|
61
|
+
"actor_type": ActorType.EXTERNAL_ATTACKER,
|
|
62
|
+
"description": (
|
|
63
|
+
"Adversary with no authenticated access who interacts with the "
|
|
64
|
+
"agent system through public-facing interfaces or indirect channels."
|
|
65
|
+
),
|
|
66
|
+
"capabilities": [
|
|
67
|
+
ActorCapability.CRAFT_PROMPTS,
|
|
68
|
+
ActorCapability.POISON_DOCUMENTS,
|
|
69
|
+
ActorCapability.EXFILTRATE_DATA,
|
|
70
|
+
],
|
|
71
|
+
"entry_points": ["public_api", "user_input", "web_content", "external_mcp"],
|
|
72
|
+
"sophistication": 3,
|
|
73
|
+
"is_internal": False,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"actor_id": "act_mal_user",
|
|
77
|
+
"name": "Malicious User",
|
|
78
|
+
"actor_type": ActorType.MALICIOUS_USER,
|
|
79
|
+
"description": (
|
|
80
|
+
"Authenticated user who attempts to manipulate agent behavior "
|
|
81
|
+
"to access resources beyond their authorization."
|
|
82
|
+
),
|
|
83
|
+
"capabilities": [
|
|
84
|
+
ActorCapability.CRAFT_PROMPTS,
|
|
85
|
+
ActorCapability.ESCALATE_PRIVILEGES,
|
|
86
|
+
ActorCapability.EXFILTRATE_DATA,
|
|
87
|
+
],
|
|
88
|
+
"entry_points": ["user_input", "task_description", "file_upload"],
|
|
89
|
+
"sophistication": 2,
|
|
90
|
+
"is_internal": False,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"actor_id": "act_compromised_agent",
|
|
94
|
+
"name": "Compromised Agent",
|
|
95
|
+
"actor_type": ActorType.COMPROMISED_AGENT,
|
|
96
|
+
"description": (
|
|
97
|
+
"A sub-agent that has been manipulated (via prompt injection or "
|
|
98
|
+
"tool poisoning) to act outside its delegated authority."
|
|
99
|
+
),
|
|
100
|
+
"capabilities": [
|
|
101
|
+
ActorCapability.INJECT_CONTEXT,
|
|
102
|
+
ActorCapability.ESCALATE_PRIVILEGES,
|
|
103
|
+
ActorCapability.MANIPULATE_DELEGATION,
|
|
104
|
+
ActorCapability.EXFILTRATE_DATA,
|
|
105
|
+
],
|
|
106
|
+
"entry_points": ["sub_agent_context", "delegation_chain", "tool_response"],
|
|
107
|
+
"sophistication": 4,
|
|
108
|
+
"is_internal": True,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"actor_id": "act_mal_mcp",
|
|
112
|
+
"name": "Malicious MCP Server",
|
|
113
|
+
"actor_type": ActorType.MALICIOUS_MCP_SERVER,
|
|
114
|
+
"description": (
|
|
115
|
+
"An external MCP server that returns crafted responses designed "
|
|
116
|
+
"to inject malicious instructions into the agent context."
|
|
117
|
+
),
|
|
118
|
+
"capabilities": [
|
|
119
|
+
ActorCapability.INJECT_CONTEXT,
|
|
120
|
+
ActorCapability.POISON_DOCUMENTS,
|
|
121
|
+
ActorCapability.INTERCEPT_RESPONSES,
|
|
122
|
+
],
|
|
123
|
+
"entry_points": ["mcp_response", "external_api_response", "tool_output"],
|
|
124
|
+
"sophistication": 4,
|
|
125
|
+
"is_internal": False,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"actor_id": "act_poisoned_doc",
|
|
129
|
+
"name": "Poisoned Document",
|
|
130
|
+
"actor_type": ActorType.POISONED_DOCUMENT,
|
|
131
|
+
"description": (
|
|
132
|
+
"A document (web page, PDF, email) that contains embedded "
|
|
133
|
+
"instructions targeting an agent that will process it."
|
|
134
|
+
),
|
|
135
|
+
"capabilities": [
|
|
136
|
+
ActorCapability.CRAFT_PROMPTS,
|
|
137
|
+
ActorCapability.INJECT_CONTEXT,
|
|
138
|
+
],
|
|
139
|
+
"entry_points": ["web_content", "file_system", "email", "rag_source"],
|
|
140
|
+
"sophistication": 1,
|
|
141
|
+
"is_internal": False,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"actor_id": "act_poisoned_rag",
|
|
145
|
+
"name": "Poisoned RAG Source",
|
|
146
|
+
"actor_type": ActorType.POISONED_RAG_SOURCE,
|
|
147
|
+
"description": (
|
|
148
|
+
"A vector database or document store that has been poisoned "
|
|
149
|
+
"with adversarial content designed to influence agent reasoning."
|
|
150
|
+
),
|
|
151
|
+
"capabilities": [
|
|
152
|
+
ActorCapability.INJECT_CONTEXT,
|
|
153
|
+
ActorCapability.POISON_DOCUMENTS,
|
|
154
|
+
],
|
|
155
|
+
"entry_points": ["rag_retrieval", "vector_db_query", "knowledge_base"],
|
|
156
|
+
"sophistication": 3,
|
|
157
|
+
"is_internal": False,
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"actor_id": "act_supply_chain",
|
|
161
|
+
"name": "Supply Chain Attacker",
|
|
162
|
+
"actor_type": ActorType.SUPPLY_CHAIN_ATTACKER,
|
|
163
|
+
"description": (
|
|
164
|
+
"Attacker who compromises a dependency, tool, or external service "
|
|
165
|
+
"used by the agent system."
|
|
166
|
+
),
|
|
167
|
+
"capabilities": [
|
|
168
|
+
ActorCapability.COMPROMISE_TOOLS,
|
|
169
|
+
ActorCapability.INTERCEPT_RESPONSES,
|
|
170
|
+
ActorCapability.EXFILTRATE_DATA,
|
|
171
|
+
],
|
|
172
|
+
"entry_points": ["package_dependency", "external_service", "third_party_api"],
|
|
173
|
+
"sophistication": 5,
|
|
174
|
+
"is_internal": False,
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"actor_id": "act_insider",
|
|
178
|
+
"name": "Insider Threat",
|
|
179
|
+
"actor_type": ActorType.INSIDER_THREAT,
|
|
180
|
+
"description": (
|
|
181
|
+
"A trusted internal actor (employee, contractor) who misuses "
|
|
182
|
+
"legitimate access to agent capabilities or data."
|
|
183
|
+
),
|
|
184
|
+
"capabilities": [
|
|
185
|
+
ActorCapability.ESCALATE_PRIVILEGES,
|
|
186
|
+
ActorCapability.EXFILTRATE_DATA,
|
|
187
|
+
ActorCapability.MANIPULATE_DELEGATION,
|
|
188
|
+
],
|
|
189
|
+
"entry_points": ["authenticated_api", "admin_interface", "direct_db_access"],
|
|
190
|
+
"sophistication": 3,
|
|
191
|
+
"is_internal": True,
|
|
192
|
+
},
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
def __init__(self) -> None:
|
|
196
|
+
self._actors: dict[str, ThreatActor] = {
|
|
197
|
+
d["actor_id"]: ThreatActor(**d) for d in self._DEFAULTS
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
def register(self, actor: ThreatActor) -> None:
|
|
201
|
+
self._actors[actor.actor_id] = actor
|
|
202
|
+
|
|
203
|
+
def get(self, actor_id: str) -> ThreatActor | None:
|
|
204
|
+
return self._actors.get(actor_id)
|
|
205
|
+
|
|
206
|
+
def all(self) -> list[ThreatActor]:
|
|
207
|
+
return list(self._actors.values())
|
|
208
|
+
|
|
209
|
+
def count(self) -> int:
|
|
210
|
+
return len(self._actors)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""ThreatAnalyzer — orchestrates analysis of the full threat model."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from actshield.threatmodel.assets import AssetRegistry
|
|
7
|
+
from actshield.threatmodel.actors import ActorRegistry
|
|
8
|
+
from actshield.threatmodel.boundaries import BoundaryRegistry
|
|
9
|
+
from actshield.threatmodel.threats import ThreatCatalog, Threat
|
|
10
|
+
from actshield.threatmodel.scenarios import get_builtin_scenarios
|
|
11
|
+
from actshield.threatmodel.mitigations import build_control_coverage_map, get_all_controls
|
|
12
|
+
from actshield.threatmodel.models import (
|
|
13
|
+
ThreatModel,
|
|
14
|
+
AnalysisResult,
|
|
15
|
+
ThreatSeverity,
|
|
16
|
+
)
|
|
17
|
+
from actshield.threatmodel.scoring import ThreatScorer
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ThreatAnalyzer:
|
|
21
|
+
"""Main threat analysis engine.
|
|
22
|
+
|
|
23
|
+
Aggregates assets, actors, boundaries, threats, and scenarios into
|
|
24
|
+
a structured AnalysisResult that can be rendered or exported.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
system_name: str = "ActShield-Monitored Agent System",
|
|
30
|
+
asset_registry: Optional[AssetRegistry] = None,
|
|
31
|
+
actor_registry: Optional[ActorRegistry] = None,
|
|
32
|
+
boundary_registry: Optional[BoundaryRegistry] = None,
|
|
33
|
+
threat_catalog: Optional[ThreatCatalog] = None,
|
|
34
|
+
) -> None:
|
|
35
|
+
self.system_name = system_name
|
|
36
|
+
self.assets = asset_registry or AssetRegistry()
|
|
37
|
+
self.actors = actor_registry or ActorRegistry()
|
|
38
|
+
self.boundaries = boundary_registry or BoundaryRegistry()
|
|
39
|
+
self.threats = threat_catalog or ThreatCatalog()
|
|
40
|
+
self.scorer = ThreatScorer()
|
|
41
|
+
|
|
42
|
+
def get_model(self) -> ThreatModel:
|
|
43
|
+
"""Return a summary ThreatModel snapshot."""
|
|
44
|
+
all_threats = self.threats.all()
|
|
45
|
+
all_scenarios = get_builtin_scenarios()
|
|
46
|
+
return ThreatModel(
|
|
47
|
+
system_name=self.system_name,
|
|
48
|
+
asset_count=self.assets.count(),
|
|
49
|
+
actor_count=self.actors.count(),
|
|
50
|
+
boundary_count=self.boundaries.count(),
|
|
51
|
+
threat_count=self.threats.count(),
|
|
52
|
+
scenario_count=len(all_scenarios),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def get_threat(self, threat_id: str) -> Threat:
|
|
56
|
+
threat = self.threats.get(threat_id)
|
|
57
|
+
if threat is None:
|
|
58
|
+
raise ValueError(f"Threat not found: {threat_id}")
|
|
59
|
+
return threat
|
|
60
|
+
|
|
61
|
+
def list_threats(self, severity_filter: Optional[str] = None) -> list[Threat]:
|
|
62
|
+
all_threats = self.threats.all()
|
|
63
|
+
if severity_filter:
|
|
64
|
+
try:
|
|
65
|
+
sev = ThreatSeverity(severity_filter.upper())
|
|
66
|
+
return [t for t in all_threats if t.severity == sev]
|
|
67
|
+
except ValueError:
|
|
68
|
+
pass
|
|
69
|
+
return all_threats
|
|
70
|
+
|
|
71
|
+
def analyze(self) -> AnalysisResult:
|
|
72
|
+
"""Run the full threat analysis and return a structured result."""
|
|
73
|
+
all_threats = self.threats.all()
|
|
74
|
+
all_scenarios = get_builtin_scenarios()
|
|
75
|
+
|
|
76
|
+
# Build model summary
|
|
77
|
+
model = self.get_model()
|
|
78
|
+
|
|
79
|
+
# Group threats by severity
|
|
80
|
+
threats_by_severity: dict[str, list[dict]] = {s.value: [] for s in ThreatSeverity}
|
|
81
|
+
for threat in all_threats:
|
|
82
|
+
threats_by_severity[threat.severity.value].append(threat.to_dict())
|
|
83
|
+
|
|
84
|
+
# Collect all control IDs referenced across all threats
|
|
85
|
+
all_control_ids: list[str] = []
|
|
86
|
+
for threat in all_threats:
|
|
87
|
+
all_control_ids.extend(threat.actshield_controls)
|
|
88
|
+
|
|
89
|
+
# Build coverage map
|
|
90
|
+
control_coverage = build_control_coverage_map(all_control_ids)
|
|
91
|
+
|
|
92
|
+
# Residual risks: threats where controls don't prevent
|
|
93
|
+
from actshield.threatmodel.models import ControlEffectiveness
|
|
94
|
+
residual_risks = [
|
|
95
|
+
{
|
|
96
|
+
"threat_id": t.threat_id,
|
|
97
|
+
"name": t.name,
|
|
98
|
+
"severity": t.severity.value,
|
|
99
|
+
"residual_score": self.scorer.residual_score(t),
|
|
100
|
+
"residual_risk": t.residual_risk,
|
|
101
|
+
"control_effectiveness": t.control_effectiveness.value,
|
|
102
|
+
}
|
|
103
|
+
for t in all_threats
|
|
104
|
+
if t.control_effectiveness not in (
|
|
105
|
+
ControlEffectiveness.PREVENTS,
|
|
106
|
+
)
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
# Build attack paths from scenarios
|
|
110
|
+
attack_paths = [
|
|
111
|
+
{
|
|
112
|
+
"scenario_id": s.scenario_id,
|
|
113
|
+
"name": s.name,
|
|
114
|
+
"severity": s.severity.value,
|
|
115
|
+
"step_count": len(s.steps),
|
|
116
|
+
"enforcement": s.actshield_enforcement,
|
|
117
|
+
"threat_ids": s.threat_ids,
|
|
118
|
+
}
|
|
119
|
+
for s in all_scenarios
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
overall_risk_score = self.scorer.overall_risk_score(all_threats)
|
|
123
|
+
|
|
124
|
+
return AnalysisResult(
|
|
125
|
+
model=model,
|
|
126
|
+
threats_by_severity=threats_by_severity,
|
|
127
|
+
control_coverage=control_coverage,
|
|
128
|
+
residual_risks=residual_risks,
|
|
129
|
+
attack_paths=attack_paths,
|
|
130
|
+
overall_risk_score=overall_risk_score,
|
|
131
|
+
)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Threat model assets — sensitive resources that must be protected."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AssetSensitivity(str, Enum):
|
|
11
|
+
CRITICAL = "CRITICAL" # Breach = catastrophic impact
|
|
12
|
+
HIGH = "HIGH" # Breach = significant harm
|
|
13
|
+
MEDIUM = "MEDIUM" # Breach = moderate harm
|
|
14
|
+
LOW = "LOW" # Breach = limited harm
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Asset(BaseModel):
|
|
18
|
+
"""A sensitive resource in the agent system that requires protection."""
|
|
19
|
+
asset_id: str
|
|
20
|
+
name: str
|
|
21
|
+
description: str
|
|
22
|
+
sensitivity: AssetSensitivity
|
|
23
|
+
owner: str = "system"
|
|
24
|
+
allowed_agents: list[str] = Field(default_factory=list)
|
|
25
|
+
allowed_operations: list[str] = Field(default_factory=list)
|
|
26
|
+
trust_boundary: str = "internal"
|
|
27
|
+
# Business impact if compromised
|
|
28
|
+
impact_confidentiality: str = "unknown"
|
|
29
|
+
impact_integrity: str = "unknown"
|
|
30
|
+
impact_availability: str = "unknown"
|
|
31
|
+
# ActShield tool name that protects this asset (if any)
|
|
32
|
+
protected_by_tool: str | None = None
|
|
33
|
+
|
|
34
|
+
def to_dict(self) -> dict[str, Any]:
|
|
35
|
+
return self.model_dump(mode="json")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AssetRegistry:
|
|
39
|
+
"""Registry of known sensitive assets in the monitored system."""
|
|
40
|
+
|
|
41
|
+
# Default built-in assets for a typical enterprise agent deployment
|
|
42
|
+
_DEFAULTS: list[dict[str, Any]] = [
|
|
43
|
+
{
|
|
44
|
+
"asset_id": "ast_creds",
|
|
45
|
+
"name": "Credentials & API Keys",
|
|
46
|
+
"description": "Service account tokens, API keys, OAuth secrets used by agents",
|
|
47
|
+
"sensitivity": AssetSensitivity.CRITICAL,
|
|
48
|
+
"owner": "platform",
|
|
49
|
+
"allowed_agents": ["orchestrator"],
|
|
50
|
+
"allowed_operations": ["read"],
|
|
51
|
+
"trust_boundary": "internal",
|
|
52
|
+
"impact_confidentiality": "Full system compromise possible",
|
|
53
|
+
"impact_integrity": "Attacker can issue authenticated requests",
|
|
54
|
+
"impact_availability": "Token revocation required",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"asset_id": "ast_customer_db",
|
|
58
|
+
"name": "Customer Database",
|
|
59
|
+
"description": "PII, financial data, and customer records",
|
|
60
|
+
"sensitivity": AssetSensitivity.CRITICAL,
|
|
61
|
+
"owner": "data-team",
|
|
62
|
+
"allowed_agents": ["analysis-agent"],
|
|
63
|
+
"allowed_operations": ["read"],
|
|
64
|
+
"trust_boundary": "internal",
|
|
65
|
+
"impact_confidentiality": "Regulatory breach, customer harm",
|
|
66
|
+
"impact_integrity": "Data corruption or fraud",
|
|
67
|
+
"impact_availability": "Service disruption",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"asset_id": "ast_sys_prompts",
|
|
71
|
+
"name": "System Prompts & Agent Instructions",
|
|
72
|
+
"description": "Confidential agent instructions, personas, and behavioral constraints",
|
|
73
|
+
"sensitivity": AssetSensitivity.HIGH,
|
|
74
|
+
"owner": "platform",
|
|
75
|
+
"allowed_agents": ["orchestrator"],
|
|
76
|
+
"allowed_operations": ["read"],
|
|
77
|
+
"trust_boundary": "internal",
|
|
78
|
+
"impact_confidentiality": "Enables adversarial prompt engineering",
|
|
79
|
+
"impact_integrity": "Behavioral manipulation possible",
|
|
80
|
+
"impact_availability": "Low",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"asset_id": "ast_internal_docs",
|
|
84
|
+
"name": "Internal Documents & Source Code",
|
|
85
|
+
"description": "Proprietary documentation, source code, and internal knowledge bases",
|
|
86
|
+
"sensitivity": AssetSensitivity.HIGH,
|
|
87
|
+
"owner": "engineering",
|
|
88
|
+
"allowed_agents": ["research-agent", "analysis-agent"],
|
|
89
|
+
"allowed_operations": ["read"],
|
|
90
|
+
"trust_boundary": "internal",
|
|
91
|
+
"impact_confidentiality": "IP theft, competitive harm",
|
|
92
|
+
"impact_integrity": "Sabotage possible",
|
|
93
|
+
"impact_availability": "Medium",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"asset_id": "ast_cloud_resources",
|
|
97
|
+
"name": "Cloud Infrastructure Resources",
|
|
98
|
+
"description": "AWS/GCP/Azure APIs, compute, storage, networking",
|
|
99
|
+
"sensitivity": AssetSensitivity.CRITICAL,
|
|
100
|
+
"owner": "infrastructure",
|
|
101
|
+
"allowed_agents": ["orchestrator"],
|
|
102
|
+
"allowed_operations": ["read", "limited-write"],
|
|
103
|
+
"trust_boundary": "cloud-boundary",
|
|
104
|
+
"impact_confidentiality": "Data exfiltration at scale",
|
|
105
|
+
"impact_integrity": "Infrastructure destruction",
|
|
106
|
+
"impact_availability": "Full service outage",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"asset_id": "ast_agent_authority",
|
|
110
|
+
"name": "Agent Authority Grants",
|
|
111
|
+
"description": "Delegated permissions and authority scopes assigned to agents",
|
|
112
|
+
"sensitivity": AssetSensitivity.HIGH,
|
|
113
|
+
"owner": "platform",
|
|
114
|
+
"allowed_agents": ["orchestrator"],
|
|
115
|
+
"allowed_operations": ["read", "delegate"],
|
|
116
|
+
"trust_boundary": "internal",
|
|
117
|
+
"impact_confidentiality": "Low",
|
|
118
|
+
"impact_integrity": "Privilege escalation possible",
|
|
119
|
+
"impact_availability": "Low",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"asset_id": "ast_rag_sources",
|
|
123
|
+
"name": "RAG Knowledge Sources",
|
|
124
|
+
"description": "Vector databases, document stores used for retrieval-augmented generation",
|
|
125
|
+
"sensitivity": AssetSensitivity.MEDIUM,
|
|
126
|
+
"owner": "ai-team",
|
|
127
|
+
"allowed_agents": ["research-agent", "analysis-agent"],
|
|
128
|
+
"allowed_operations": ["read", "query"],
|
|
129
|
+
"trust_boundary": "internal",
|
|
130
|
+
"impact_confidentiality": "Sensitive doc exposure",
|
|
131
|
+
"impact_integrity": "Poisoned retrieval results affect agent reasoning",
|
|
132
|
+
"impact_availability": "Degraded agent quality",
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"asset_id": "ast_audit_logs",
|
|
136
|
+
"name": "Security Audit Logs",
|
|
137
|
+
"description": "ActShield event logs, forensic traces, and security evidence",
|
|
138
|
+
"sensitivity": AssetSensitivity.HIGH,
|
|
139
|
+
"owner": "security-team",
|
|
140
|
+
"allowed_agents": [],
|
|
141
|
+
"allowed_operations": ["read"],
|
|
142
|
+
"trust_boundary": "internal",
|
|
143
|
+
"impact_confidentiality": "Attacker can study detection patterns",
|
|
144
|
+
"impact_integrity": "Evidence tampering breaks forensics",
|
|
145
|
+
"impact_availability": "Incident response compromised",
|
|
146
|
+
},
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
def __init__(self) -> None:
|
|
150
|
+
self._assets: dict[str, Asset] = {
|
|
151
|
+
d["asset_id"]: Asset(**d) for d in self._DEFAULTS
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
def register(self, asset: Asset) -> None:
|
|
155
|
+
self._assets[asset.asset_id] = asset
|
|
156
|
+
|
|
157
|
+
def get(self, asset_id: str) -> Asset | None:
|
|
158
|
+
return self._assets.get(asset_id)
|
|
159
|
+
|
|
160
|
+
def all(self) -> list[Asset]:
|
|
161
|
+
return list(self._assets.values())
|
|
162
|
+
|
|
163
|
+
def by_sensitivity(self, sensitivity: AssetSensitivity) -> list[Asset]:
|
|
164
|
+
return [a for a in self._assets.values() if a.sensitivity == sensitivity]
|
|
165
|
+
|
|
166
|
+
def count(self) -> int:
|
|
167
|
+
return len(self._assets)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Trust and authority boundaries for the agent system threat model."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BoundaryType(str, Enum):
|
|
11
|
+
TRUST = "TRUST" # Who/what is trusted at this boundary
|
|
12
|
+
AUTHORITY = "AUTHORITY" # What operations are permitted
|
|
13
|
+
DATA = "DATA" # What data can cross this boundary
|
|
14
|
+
NETWORK = "NETWORK" # Network-level isolation
|
|
15
|
+
EXECUTION = "EXECUTION" # Sandbox / runtime isolation
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TrustBoundary(BaseModel):
|
|
19
|
+
"""A boundary in the agent system that separates trust zones."""
|
|
20
|
+
boundary_id: str
|
|
21
|
+
name: str
|
|
22
|
+
boundary_type: BoundaryType
|
|
23
|
+
description: str
|
|
24
|
+
# Zones on either side
|
|
25
|
+
trusted_zone: str
|
|
26
|
+
untrusted_zone: str
|
|
27
|
+
# Controls enforced at this boundary by ActShield
|
|
28
|
+
controls: list[str] = Field(default_factory=list)
|
|
29
|
+
# Entry points that cross this boundary
|
|
30
|
+
crossing_entry_points: list[str] = Field(default_factory=list)
|
|
31
|
+
|
|
32
|
+
def to_dict(self) -> dict[str, Any]:
|
|
33
|
+
return self.model_dump(mode="json")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BoundaryRegistry:
|
|
37
|
+
"""Registry of trust boundaries in the agent system."""
|
|
38
|
+
|
|
39
|
+
_DEFAULTS: list[dict[str, Any]] = [
|
|
40
|
+
{
|
|
41
|
+
"boundary_id": "bnd_ext_int",
|
|
42
|
+
"name": "External → Internal",
|
|
43
|
+
"boundary_type": BoundaryType.TRUST,
|
|
44
|
+
"description": (
|
|
45
|
+
"Primary boundary between external internet and internal agent "
|
|
46
|
+
"infrastructure. All external MCP responses, web content, and "
|
|
47
|
+
"user inputs cross this boundary."
|
|
48
|
+
),
|
|
49
|
+
"trusted_zone": "internal",
|
|
50
|
+
"untrusted_zone": "external",
|
|
51
|
+
"controls": ["provenance_tracking", "taint_marking", "mcp_gateway", "http_gateway"],
|
|
52
|
+
"crossing_entry_points": [
|
|
53
|
+
"external_mcp_response", "web_content", "user_input", "external_api"
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"boundary_id": "bnd_agent_agent",
|
|
58
|
+
"name": "Agent → Sub-Agent Delegation",
|
|
59
|
+
"boundary_type": BoundaryType.AUTHORITY,
|
|
60
|
+
"description": (
|
|
61
|
+
"Authority boundary enforced when an orchestrator agent delegates "
|
|
62
|
+
"tasks to sub-agents. Authority cannot be escalated beyond the "
|
|
63
|
+
"delegating agent's effective authority."
|
|
64
|
+
),
|
|
65
|
+
"trusted_zone": "orchestrator",
|
|
66
|
+
"untrusted_zone": "sub-agent",
|
|
67
|
+
"controls": ["delegation_tracking", "authority_containment", "effective_authority_check"],
|
|
68
|
+
"crossing_entry_points": ["delegation_request", "sub_task_creation"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"boundary_id": "bnd_context_tool",
|
|
72
|
+
"name": "Context → Tool Execution",
|
|
73
|
+
"boundary_type": BoundaryType.DATA,
|
|
74
|
+
"description": (
|
|
75
|
+
"Critical boundary between agent context (which may be tainted "
|
|
76
|
+
"by external sources) and privileged tool execution."
|
|
77
|
+
),
|
|
78
|
+
"trusted_zone": "tool_executor",
|
|
79
|
+
"untrusted_zone": "agent_context",
|
|
80
|
+
"controls": [
|
|
81
|
+
"taint_tracking", "provenance_check", "intent_analysis",
|
|
82
|
+
"policy_evaluation", "tool_interception"
|
|
83
|
+
],
|
|
84
|
+
"crossing_entry_points": ["tool_request", "tool_call"],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"boundary_id": "bnd_mcp_context",
|
|
88
|
+
"name": "MCP Server → Agent Context",
|
|
89
|
+
"boundary_type": BoundaryType.DATA,
|
|
90
|
+
"description": (
|
|
91
|
+
"Boundary between external MCP server responses and the agent "
|
|
92
|
+
"context window. Malicious MCP responses can inject instructions."
|
|
93
|
+
),
|
|
94
|
+
"trusted_zone": "agent_context",
|
|
95
|
+
"untrusted_zone": "mcp_response",
|
|
96
|
+
"controls": ["mcp_gateway", "taint_marking", "provenance_tracking", "intent_analysis"],
|
|
97
|
+
"crossing_entry_points": ["mcp_tool_response", "mcp_resource_content"],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"boundary_id": "bnd_agent_db",
|
|
101
|
+
"name": "Agent → Sensitive Database",
|
|
102
|
+
"boundary_type": BoundaryType.AUTHORITY,
|
|
103
|
+
"description": (
|
|
104
|
+
"Authority boundary protecting sensitive databases from unauthorized "
|
|
105
|
+
"agent access. Requires explicit authority grant and clean context."
|
|
106
|
+
),
|
|
107
|
+
"trusted_zone": "database",
|
|
108
|
+
"untrusted_zone": "agent",
|
|
109
|
+
"controls": [
|
|
110
|
+
"authority_containment", "taint_check", "policy_evaluation",
|
|
111
|
+
"protected_tool", "audit_logging"
|
|
112
|
+
],
|
|
113
|
+
"crossing_entry_points": ["database_tool_call"],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"boundary_id": "bnd_rag_context",
|
|
117
|
+
"name": "RAG Source → Agent Context",
|
|
118
|
+
"boundary_type": BoundaryType.DATA,
|
|
119
|
+
"description": (
|
|
120
|
+
"Boundary between retrieval-augmented sources and the agent context. "
|
|
121
|
+
"Poisoned documents retrieved via RAG can influence agent reasoning."
|
|
122
|
+
),
|
|
123
|
+
"trusted_zone": "agent_context",
|
|
124
|
+
"untrusted_zone": "rag_retrieval",
|
|
125
|
+
"controls": ["provenance_tracking", "taint_marking", "source_attribution"],
|
|
126
|
+
"crossing_entry_points": ["rag_retrieval_result", "vector_db_response"],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"boundary_id": "bnd_internal_cloud",
|
|
130
|
+
"name": "Internal → Cloud Infrastructure",
|
|
131
|
+
"boundary_type": BoundaryType.NETWORK,
|
|
132
|
+
"description": (
|
|
133
|
+
"Network boundary between internal agent execution and cloud "
|
|
134
|
+
"infrastructure APIs. Unauthorized cloud API calls can cause "
|
|
135
|
+
"significant resource abuse."
|
|
136
|
+
),
|
|
137
|
+
"trusted_zone": "cloud",
|
|
138
|
+
"untrusted_zone": "agent_network",
|
|
139
|
+
"controls": ["authority_containment", "policy_evaluation", "http_gateway"],
|
|
140
|
+
"crossing_entry_points": ["cloud_api_call", "infrastructure_tool"],
|
|
141
|
+
},
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
def __init__(self) -> None:
|
|
145
|
+
self._boundaries: dict[str, TrustBoundary] = {
|
|
146
|
+
d["boundary_id"]: TrustBoundary(**d) for d in self._DEFAULTS
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
def register(self, boundary: TrustBoundary) -> None:
|
|
150
|
+
self._boundaries[boundary.boundary_id] = boundary
|
|
151
|
+
|
|
152
|
+
def get(self, boundary_id: str) -> TrustBoundary | None:
|
|
153
|
+
return self._boundaries.get(boundary_id)
|
|
154
|
+
|
|
155
|
+
def all(self) -> list[TrustBoundary]:
|
|
156
|
+
return list(self._boundaries.values())
|
|
157
|
+
|
|
158
|
+
def count(self) -> int:
|
|
159
|
+
return len(self._boundaries)
|
|
160
|
+
|
|
161
|
+
def for_entry_point(self, entry_point: str) -> list[TrustBoundary]:
|
|
162
|
+
return [
|
|
163
|
+
b for b in self._boundaries.values()
|
|
164
|
+
if entry_point in b.crossing_entry_points
|
|
165
|
+
]
|